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. PMP-产品范围与项目范围区别

    如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 1.产品范围--某项产品.服务或成果所具有的特性和功能. 2.项目范围--为交付具有 ...

  2. 来自Google产品管理和营销高级副总裁Jonathan Rosenberg的42条军规(转)

    #35 营造一个说 yes 的文化 你想要建立一个充满正能量和积极思考的地方.“组织里有阻碍变革发生的抗体.所以许多大公司无法创新.如果你是一个创新者,你就变成了病毒,所有的抗体都想杀死你.”在这种情 ...

  3. Linux下软件安装,卸载,管理

    一. 软件安装包的类型 通常Linux应用软件的安装有五种: 1) tar+ gz包,如software-1.2.3-1.tar.gz.     他是使用UNIX系统的打包工具tar打包的. 2) r ...

  4. 如何使用编辑模板在ASPxGridView中进行新增修改(除去常规的gridviw模板编辑外)

    aspgridview模板编辑效果图: //前端代码:(核心: <Templates><EditForm>.....中间可用栅格样式布局等(随意)...</Templat ...

  5. java学习之(垃圾回收)

    程序无法精确控制java垃圾回收的时机,但依然可以强制系统进行垃圾回收--这种强制只是通知系统进行垃圾回收, 但系统是否进行垃圾回收依然不确定.大部分时候,程序强制系统垃圾回收后总会有一些效果,强制系 ...

  6. CHARINDEX用法

    CHARINDEX返回字符串中指定表达式的起始位置. 语法CHARINDEX ( e­xpression1 , e­xpression2 [ , start_location ] ) 参数e­xpre ...

  7. 保护企业的Word文档

    保护企业的Word文档 通常,我们可以对Word文件进行加密码.设置为只读.禁止复制甚至是将内容变成图片加以保护,但这仅限于个人少量文档,如果是企业每天生产大量的word文档好用这种方法就不行,今天为 ...

  8. 如果公司里有上百个表要做触发器,如果手动写代码的话。很累,所以今天写了一个小程序,自动生成mysql的触发代码。

    <?php $dbname = 'test';//数据库 $tab1 = 'user'; //执行的表 $tab2 = 'user_bak'; //被触发的表 $conn = mysql_con ...

  9. Android Malware Analysis

    A friend of mine asked me help him to examine his Android 5.0 smartphone. He did not say what's wron ...

  10. c/c++基本问题

    1. 使用g++将文件编译成库文件 g++ -c -O2 -fPIC test.cpp -o test.o && g++ -shared -Wall -o test.so test.o ...