UDP:

UDP协议没有socket之间的虚拟链路,也就是说没有“握手”阶段,只是发送接收。

可以想象成直播,直播时如果中间网络不好,不会事后重新播放之前的,而是直接跳过。

也就是说一方只负责发送,一方只负责接收,发送方不关心对方会不会接到数据。

TCP协议:可靠,传输大小无限制,但是需要建立连接后传输数据。

UDP协议:不可靠,传输大小限制在64K以下,但是不需要建立连接。

相关类:

DatagramSocket:接收和发送的数据报。

receive(DatagramPacket P)://从DatagramSocket接收数据。
send(DatagramPacket P)://从DatagramSocket发送数据。

DatagramSocket并不知道数据发送到哪里去,而是由DatagramPacket来指定。

DatagramPacket:用来承载数据的,代表数据报。

DatagramPacket(byte buf[],int length, InetAnddress addr,int port);//一个装有传送数据的数组,加一个接收方的地址以及端口。
DatagramPacket(byte buf[],int length);//只有装有数据的数组,意味着接收数据报。
/*那么反馈数据应该怎么办,DatagramSocket也不知道从哪发过来的数据。
DatagramPacket提供了3个方法:*/
InetAddress getAddress();//当接收到一个数据的时候返回发送主机IP地址。发送时反之。
Int getPort();//当接收到一个数据的时候返回发送主机端口。发送时反之。
SocketAddress getSocketAddress();//当接收到一个数据的时候返回打包成发送主机IP&PORT的SocketAddress。发送时反之。

实例:

服务端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket; public class UDPServer {
public static final int PORT = 30000;
// 定义每个数据报的最大大小为4KB
private static final int DATA_LEN = 4096;
// 定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
// 以指定字节数组创建准备接收数据的DatagramPacket对象
private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
// 定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket;
// 定义一个字符串数组,服务器端发送该数组的元素
String[] books = new String[] { "疯狂Java讲义", "轻量级Java EE企业应用实战",
"疯狂Android讲义", "疯狂Ajax讲义" }; public void init() throws IOException {
try (
// 创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket(PORT)) {
// 采用循环接收数据
for (int i = 0; i < 1000; i++) {
// 读取Socket中的数据,读到的数据放入inPacket封装的数组里
socket.receive(inPacket);
// 判断inPacket.getData()和inBuff是否是同一个数组
System.out.println(inBuff == inPacket.getData());
// 将接收到的内容转换成字符串后输出
System.out.println(new String(inBuff, 0, inPacket.getLength()));
// 从字符串数组中取出一个元素作为发送数据
byte[] sendData = books[i % 4].getBytes();
// 以指定的字节数组作为发送数据,以刚接收到的DatagramPacket的
// 源SocketAddress作为目标SocketAddress创建DatagramPacket
outPacket = new DatagramPacket(sendData, sendData.length,
inPacket.getSocketAddress());
// 发送数据
socket.send(outPacket);
}
}
} public static void main(String[] args) throws IOException {
new UDPServer().init();
}
}

客户端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner; public class UDPClient
{
// 定义发送数据报的目的地
public static final int DEST_PORT = 30000;
public static final String DEST_IP = "127.0.0.1";
// 定义每个数据报的最大大小为4KB
private static final int DATA_LEN = 4096;
// 定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
// 以指定的字节数组创建准备接收数据的DatagramPacket对象
private DatagramPacket inPacket =
new DatagramPacket(inBuff , inBuff.length);
// 定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket = null;
public void init()throws IOException
{
try(
// 创建一个客户端DatagramSocket,使用随机端口
DatagramSocket socket = new DatagramSocket())
{
// 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组
outPacket = new DatagramPacket(new byte[0] , 0
, InetAddress.getByName(DEST_IP) , DEST_PORT);
// 创建键盘输入流
Scanner scan = new Scanner(System.in);
// 不断地读取键盘输入
while(scan.hasNextLine())
{
// 将键盘输入的一行字符串转换成字节数组
byte[] buff = scan.nextLine().getBytes();
// 设置发送用的DatagramPacket中的字节数据
outPacket.setData(buff);
// 发送数据报
socket.send(outPacket);
// 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组中
socket.receive(inPacket);
System.out.println(new String(inBuff , 0
, inPacket.getLength()));
}
}
}
public static void main(String[] args)
throws IOException
{
new UDPClient().init();
}
}

运行:

  1. 打开服务端
  2. 打开客户端
  3. 在客户端窗口键盘输入后enter

MulticastSocket:

当使用UDP协议时,如果想让一个客户端发送的聊天信息被转发到其他所有的客户端则比较困难,可以考虑在服务器端使用Set集合来保存所有的客户端信息,

每当接收到一个客户端的数据报之后,程序检查该数据报的源SocketAddress是否在Set集合中,如果不在就将该SocketAddress添加到该Set集合中。

这样又涉及一个问题:可能有些客户端发送一个数据报之后永久性地退出了程序,但服务器端还将该客户端的SocketAddress保存在Set集合中……

总之,这种方式需要处理的问题比较多,编程比较烦琐。幸好Java为UDP协议提供了MulticastSocket类,通过该类可以轻松地实现多点广播。

MulticastSocket没有客户端服务端之说,都是发往广播地址中,只要join到广播地址中,那么所有MulticastSocket都会接到此数据。

MulticastSocket类是DatagramSocket的子类
JoinGroup(InetAddress mulicastAddr):将该MulticastSocket加入到广播地址中。发送广播那么我们需要用到广播地址(230.0.0.1)。
LeaveGroup(InetAddress mulicastAddr): 与JoinGroup(InetAddress mulicastAddr)相反。
SetTimeToLive(int ttl):设置数据可跨多少个网络。
 *设置ttl为1我们就在局域网内使用。

ttl我们可以在CMD命令窗口中通过ping命令可以确认到TTL对应值。

当ttl=0时,指定数据报应停留在本地主机。

当ttl=1时,指定数据报发送到局域网。

当ttl=32时,指定数据报发送到本站点的网络上。

当ttl=64时,指定数据报发送到本地区。

当ttl=128时,指定数据报发送到本大洲内。

当ttl=255时,指定数据报发送所有地方。

实例:

在原来的DatagramSocket的客户端代码中进行了修改。

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Scanner; public class MulticastSocketDemo implements Runnable {
// 定义发送数据报的目的地
public static final int DEST_PORT = 30000;
public static final String MULTICAST_IP = "230.0.0.1";
public InetAddress multicastAddr = null;
// 定义每个数据报的最大大小为4KB
private static final int DATA_LEN = 4096;
// 定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
// 以指定的字节数组创建准备接收数据的DatagramPacket对象
private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
// 定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket = null;
// 定义一个MulticastSocket对象
private MulticastSocket socket = null; public void init() throws IOException {
try {
// 创建一个MulticastSocket,必須指定端口,指定端口为DEST_PORT,
socket = new MulticastSocket(DEST_PORT);
//创建一个广播地址
multicastAddr = InetAddress.getByName(MULTICAST_IP);
// 将MulticastSocket加入到广播地址中
socket.joinGroup(multicastAddr);
// 使用在局域网中
socket.setTimeToLive(1);
// 发送的数据报回送到自身
socket.setLoopbackMode(false);
// 初始化发送用的MulticastSocket,它包含一个长度为0的字节数组
outPacket = new DatagramPacket(new byte[0], 0,multicastAddr, DEST_PORT);
// 创建接收数据的线程
new Thread(this).start();
// 创建键盘输入流
Scanner scan = new Scanner(System.in);
// 不断地读取键盘输入,没有数据时会堵塞,等待输入
while (scan.hasNextLine()) {
// 将键盘输入的一行字符串转换成字节数组
byte[] buff = scan.nextLine().getBytes();
// 设置发送用的DatagramPacket中的字节数据
outPacket.setData(buff);
// 发送数据报
socket.send(outPacket);
}
} finally {
socket.close();
}
} @Override
public void run() {
// TODO Auto-generated method stub
try {
// 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组中
while (true) {
socket.receive(inPacket);
System.out.println(new String(inBuff, 0, inPacket.getLength()));
}
} catch (IOException e) {
// TODO Auto-generated catch block
if(socket !=null){
try {
socket.leaveGroup(multicastAddr);
socket.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
e.printStackTrace();
}
} public static void main(String[] args) throws IOException {
new MulticastSocketDemo().init();
} }

运行:

  1. 打开多个此窗口
  2. 在窗口键盘输入后enter

Socket(2)的更多相关文章

  1. socket读写返回值的处理

    在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...

  2. Socket聊天程序——Common

    写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...

  3. Socket聊天程序——客户端

    写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...

  4. Socket聊天程序——服务端

    写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...

  5. Socket聊天程序——初始设计

    写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...

  6. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  7. Android Socket连接PC出错问题及解决

    最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.

  8. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  9. Mono 3.2.3 Socket功能迎来一稳定的版本

    由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...

  10. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...

随机推荐

  1. 了解Entity Framework中事务处理

    Entity Framework 6以前,框架本身并没有提供显式的事务处理方案,在EF6中提供了事务处理的API. 所有版本的EF,只要你调用SaveChanges方法进行插入.修改或删除,EF框架会 ...

  2. Exceeded maximum number of retries. Exceeded max scheduling attempts 3 for instance 7d90eb80-29e2-4238-b658-ade407ff9456. Last exception: [u'Traceback (most recent call last):\n', u' File "/usr/lib/py

    Exceeded maximum number of retries. Exceeded max scheduling attempts 3 for instance 7d90eb80-29e2-42 ...

  3. dedecms代码研究一

    dedecms相信大家一定都知道这个cms系统,功能比较强大,有比较完善的内容发布,还有内容静态化系统,还有就是它有自己独特的标签系统和模板系统.而模板系统也是其他cms系统比较难模仿的的东西,这个东 ...

  4. dell N1500 安全配置

    http://www.dell.com/Support/Article/us/en/19/HOW10832 Setting a management IP address A reachable IP ...

  5. NSString常见用法总结

    //====================NSStirng 的常见用法==================== -(void)testString { //创建格式化字符串:占位符(由一个%加一个字 ...

  6. sublineText

    https://github.com/thinkpixellab/flatland { "color_scheme": "Packages/Theme - Flatlan ...

  7. VC++2010下编译STLport,Boost

    VC++2010下编译STLport,Boost 最近在想向Boost转移,努力掌握Boost代码的过程中, STLport版本:5.2.1 Boost版本:1.4.6.1 (1.4.7.0也OK) ...

  8. Oracle 通过触发器 来创建 同步临时表 及处理 通过 自治事务 来解决 查询 基表的问题

    // 触发器 create or replace trigger tr_sync_BD_MARBASCLASS after INSERT or UPDATE on BD_MARBASCLASS for ...

  9. Android WebRTC 音视频开发总结(二)-- webrtcdemo介绍

    这节主要介绍WebRTCDemo的结构,以此来简单了解WebRTC的调用流程,转载请说明出处(博客园RTC.Blacker) 1.先看WebRTCDemo的代码结构,如下图: 2.WebRTCDemo ...

  10. javaSE第二天

    第二天    7 1:关键字(掌握)    7 2:标识符(掌握)    7 (1)就是给类,接口,方法,变量等起名字的字符序列    7 (2)组成规则:    7 (3)注意事项:    8 (4 ...