Java开发笔记(一百一十六)采用UDP协议的Socket通信
前面介绍了如何通过Socket接口传输文本与文件,在示例代码中,Socket客户端得先调用connect方法连接服务端,确认双方成功连上后才能继续运行后面的代码,这种确认机制确保客户端与服务端的的确确成功连接了,因而是可靠的网络连接,并且该可靠连接属于TCP连接。为啥这么说呢?因为TCP协议(全称“Transmission Control Protocol”,传输控制协议)不仅是一种传输层的通信协议,而且它具备面向可靠连接、以及基于字节流两大特征。之前联合Socket与ServerSocket实现消息通信的过程,正是遵从TCP协议的精神
虽然可靠连接能够保证一定会把信息送达对方,但是有时需要批量向一群目标设备发送消息,也就是俗称的“群发”,倘若每个设备都经历建立连接、发送消息、关闭连接三个步骤,整个群发操作的资源开销将是巨大的。鉴于群发功能一般为单向过程,消息发送方既不关心那些接收方是否收到消息,也不指望那些接收方会有什么反馈结果,总之消息发送方就像电台做广播那样,在固定的频率波段发送信息,它才不管别人的收音机有没有开着、有没有接收这个频道,只有收音机开着且调至对应的频道,方能收到该电台的广播节目。像这样的广播功能用到了传输层的另一种UDP协议(全称“User Datagram Protocol”,用户数据报协议),由于UDP并非可靠连接,它只管扔沙包,而不管对方有没有接到沙包,因此实现过程相较TCP要更简单,毕竟随便丢东西不费多少劲儿。
就UDP协议而言,Java给出的实现工具包括数据包套接字DatagramSocket和数据包裹DatagramPacket。其中DatagramSocket提供了设备间的数据交互动作,它的主要方法说明如下:
构造方法:对于服务端来说,构造方法需要指定待侦听的端口号;对于客户端来说,构造方法无需任何参数。
receive:该方法用于服务端接收数据。
send:该方法用于客户端发送数据。
close:关闭数据包套接字。
注意上面的receive和send两个方法,它们的输入参数类型为DatagramPacket,也就是说,必须先将数据封装为DatagramPacket格式,才能在UDO的服务端与客户端之间传输。下面是DatagramPacket的主要方法说明:
用于服务端的构造方法:此时构造方法只有两个参数,分别为字节数组及其长度。
用于客户端的构造方法:此时构造方法拥有四个参数,依次为字节数组、数组长度、数据要发往的服务器InetAddress地址、服务器的端口号。
getData:获取数据包裹里的字节数组。
getOffset:获取数据的起始偏移。
getLength:获取数据的长度。
接下来举个简单的应用案例,采取UDP协议在设备之间传输文本消息,此时的UDP服务端代码示例如下:
//演示Socket服务器的运行(UDP协议的不可靠连接)
public class TestUdpServer {
private static final int UDP_PORT = 61000; // UDP传输专用端口 public static void main(String[] args) {
startUdpServer(); // 启动UDP服务器接收文本消息
} // 启动UDP服务器接收文本消息
private static void startUdpServer() {
PrintUtils.print("UDP服务器已启动");
// 创建一个监听指定端口的DatagramSocket对象
try (DatagramSocket socket = new DatagramSocket(UDP_PORT)) {
byte[] data = new byte[1024]; // 接收数据的字节数组
// 创建一个DatagramPacket对象,并指定数据包的字节数组及其大小
DatagramPacket packet = new DatagramPacket(data, data.length);
while (true) { // 持续侦听
socket.receive(packet); // 接收到了数据包
// 把收到的数据转换为字符串。字符串构造方法的三个参数依次为:
// 已收到的数据、起始偏移、数据的长度。
String message = new String(packet.getData(),
packet.getOffset(), packet.getLength());
PrintUtils.print("UDP服务器收到消息:" + message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
原来UDP方式的服务端代码如此简洁,UDP客户端的代码同样简约,即便是发送两条消息的完整代码也只有以下数行:
//演示Socket客户端的运行(UDP协议的不可靠连接)
public class TestUdpClient {
// 以下为Socket服务器的IP和端口,根据实际情况修改
private static final String SOCKET_IP = "192.168.1.8";
private static final int UDP_PORT = 61000; // UDP传输专用端口 public static void main(String[] args) {
startUdpClient("Hello World"); // 启动UDP客户端发送文本消息
startUdpClient("你好,世界"); // 启动UDP客户端发送文本消息
} // 启动UDP客户端发送文本消息
private static void startUdpClient(String message) {
PrintUtils.print("UDP客户端发送消息:" + message);
// 创建一个DatagramSocket对象
try (DatagramSocket socket = new DatagramSocket()) {
// 根据IP地址获得对应的网络地址对象
InetAddress serverAddress = InetAddress.getByName(SOCKET_IP);
byte data[] = message.getBytes(); // 把字符串转换为字节数组
// 创建一个DatagramPacket对象,构造方法的四个参数依次为:
// 待发送的数据、数据的长度、服务器的网络地址、服务器的端口号。
DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, UDP_PORT);
socket.send(packet); // 向服务器发送数据包
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后先后运行服务端与客户端的测试代码,观察到的客户端日志如下:
12:16:12.316 main UDP客户端发送消息:Hello World
12:16:12.366 main UDP客户端发送消息:你好,世界
同时观察到下面的服务端日志:
12:15:46.998 main UDP服务器已启动
12:16:12.366 main UDP服务器收到消息:Hello World
12:16:12.368 main UDP服务器收到消息:你好,世界
根据以上的客户端日志以及服务端日志,可知通过UDP协议也成功完成了文本传输。
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(一百一十六)采用UDP协议的Socket通信的更多相关文章
- Java开发笔记(八十六)通过缓冲区读写文件
前面介绍了利用文件写入器和文件读取器来读写文件,因为FileWriter与FileReader读写的数据以字符为单位,所以这种读写文件的方式被称作“字符流I/O”,其中字母I代表输入Input,字母O ...
- Java开发笔记(二十六)方法的输出参数
前面介绍了方法的输入参数,与输入参数相对应的则为输出参数,输出参数也被称作方法的返回值,意思是经过方法的处理最终得到的运算数值.这个返回值可能是整型数,也可能是双精度数,也可能是数组等其它类型,甚至允 ...
- Java开发笔记(三十六)字符串的常用方法
不管是给字符串赋值,还是对字符串格式化,都属于往字符串填充内容,一旦内容填充完毕,则需开展进一步的处理.譬如一段Word文本,常见的加工操作就有查找.替换.追加.截取等等,按照字符串的处理结果异同,可 ...
- Java开发笔记(四十六)类的构造方法
前面介绍了如何定义一个简单的类,以及它的成员属性和成员方法,从示例代码可以看到,不管是OrangeSimple还是OrangeMember,都要先利用关键字new创建一个实例,然后才能通过实例名称访问 ...
- Java开发笔记(五十六)利用枚举类型实现高级常量
前面介绍了联合利用final和static可实现常量的定义,该方式用于简单的常量倒还凑合,要是用于复杂的.安全性高的常量,那就力不从心了.例如以下几种情况,final结合static的方式便缺乏应对之 ...
- Java开发笔记(七十六)如何预防异常的产生
每个程序员都希望自己的程序稳定运行,不要隔三岔五出什么差错,可是程序运行时冒出来的各种异常着实烦人,令人不胜其扰.虽然可以在代码中补上try/catch语句捕捉异常,但毕竟属于事后的补救措施.与其后知 ...
- Java开发笔记(四十)日期与字符串的互相转换
前面介绍了如何通过Date工具获取各个时间数值,但是用户更喜欢形如“2018-11-24 23:04:18”这种结构清晰.简洁明了的字符串,而非啰里八唆依次汇报每个时间单位及其数值的描述.既然日期时间 ...
- Java开发笔记(三十二)字符型与整型相互转化
前面提到字符类型是一种新的变量类型,然而编码实践的过程中却发现,某个具体的字符值居然可以赋值给整型变量!就像下面的例子代码那样,把字符值赋给整型变量,编译器不但没报错,而且还能正常运行! // 字符允 ...
- Java开发笔记(八十八)文件字节I/O流
前面介绍了如何使用字符流读写文件,并指出字符流工具的处理局限,进而给出随机文件工具加以改进.随机文件工具除了支持访问文件内部的任意位置,更关键的一点是通过字节数组读写文件数据,采取字节方式比起字符方式 ...
随机推荐
- Bzoj 1927: [Sdoi2010]星际竞速(网络流)
1927: [Sdoi2010]星际竞速 Time Limit: 20 Sec Memory Limit: 259 MB Description 10年一度的银河系赛车大赛又要开始了.作为全银河最盛大 ...
- CodeChef November Challenge 2019 Division 1题解
传送门 AFO前的最后一场CC了--好好打吧-- \(SIMGAM\) 偶数行的必定两人平分,所以只要抢奇数行中间那个就行了 这题怎么被爆破了 //quming #include<bits/st ...
- IDEA 重新 build Project
- 【2019.11.13】SDN上机第3次作业
参考资料:https://www.cnblogs.com/fjlinww/p/11834092.html 实验一 利用Mininet仿真平台构建如下图所示的网络拓扑,配置主机h1和h2的IP地址(h1 ...
- 帝国CMS排行榜调用标签
[e:loop={0,9,4,0,'newstime>UNIX_TIMESTAMP()-86400*30','onclick desc'}]<li><a href=" ...
- jmeter(四十四)常用性能指标分析
概述 我们在用jmeter做性能测试的时候,有一些关键性的性能指标需要去分析.但是由于开源工具本身的局限性,这些指标在工具中的命名极易对我们造成混淆.所以我们需要对这些指标一一进行剖析. 指标分析 响 ...
- 20189220 余超《Linux内核原理与分析》第一周作业
实验一 Linux系统简介 通过实验一主要是学习到了Linux 的历史简介,linux与windows之间的区别,主要是免费和收费,软件和支持,安全性,使用习惯,可制定性,应用范畴等.linux具有稳 ...
- idea docker docker-compose发布springboot站点到tomcat
允许docker被远程访问 见:https://www.cnblogs.com/wintersoft/p/10921396.html 教程:https://spring.io/guides/gs/sp ...
- Predicting effects of noncoding variants with deep learning–based sequence model | 基于深度学习的序列模型预测非编码区变异的影响
Predicting effects of noncoding variants with deep learning–based sequence model PDF Interpreting no ...
- mysql性能测试-------重要!!!
我们在做性能测试的目的是什么,就是要测出一个系统的瓶颈在哪里,到底是哪里影响了我们系统的性能,找到问题,然后解决它.当然一个系统由很多东西一起组合到一起,应用程序.数据库.服务器.中中间件等等很多东西 ...