UDP局域网通信的Java实现及Android平台尝试

coder-ice 2020-11-11 19:48:50
通信 局域网 UDP 局域 网通


局域网通信已经很少被他人所提及了,我曾经还尝试过通过蓝牙构建通信网络,这次有机会尝试UDP局域网通信,在这里把一些基本过程和在Android平台上的问题记录一下。

1. UDP基础知识

1.1 什么是UDP

Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法。RFC 768 描述了 UDP。
Internet 的传输层有两个主要协议,互为补充。无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的的事情。面向连接的是 TCP,该协议几乎做了所有的事情。
——《百度百科》

根据百度百科的解释,UDP是一个数据传输协议,面向无连接的数据传输方式,说明此协议丢包概率较高,不适合复杂的网络环境。UDP报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但是正因为UDP协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序。在局域网中,数据的到达率几乎是可以保证的,因此UDP在局域网通信中拥有比TCP更重要的地位。

1.2 UDP通信基本流程

  1. 设定好统一的端口号;

  2. 初始化绑定指定端口号的数据接收器;

  3. 指定接收方的IP地址;

  4. 准备好轻量数据;

  5. 发送数据至指定的IP地址;

  6. 数据接收器触发后续逻辑。

2. UDP局域网通信的Java实现

2.1 UDP广播

UDP广播的实现较为简单,其接收方的IP地址固定为255.255.255.255,端口号任选,保证发送方与接收方端口号一致且不与其他程序冲突即可,代码示例如下:

public class UDPManager {
public static final int BUFFER_SIZE = 2048;
public DatagramSocket socket;
public void init() {
try {
//先创建一个绑定了端口号为9527的DatagramSocket
socket = new DatagramSocket(9527);
//开启数据接收器
openReceiver();
//发送广播消息
sendBroadcast("Hello World!");
} catch (Exception e) {
e.printStackTrace();
}
}
public void openReceiver() {
//在子线程中循环接收数据
new Thread(new Runnable() {
@override
public void run() {
byte[] buffer = new byte[BUFFER_SIZE];
DatagramPacket dp = new DatagramPacket(buffer, BUFFER_SIZE);
while(socket != null) {
try {
socket.receive(dp);
System.out.println(new String(buffer));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start;
}
public void sendBroadcast(String dataStr) throws IOException {
//发送广播消息,消息内容为dataStr
if (socket != null) {
byte[] buffer = dataStr.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 9527);
socket.send(packet);
}
}
}

2.2 UDP单播

UDP单播的实现与广播类似,其接收方的IP地址需发送消息时传入,端口号任选,保证发送方与接收方端口号一致且不与其他程序冲突即可,在2.1中展示的UDPManager类中增加单播发送方法即可,代码示例如下:

public class UDPManager {
//···
public void sendSingle(String dataStr, String targetIP) throws IOException {
//发送单播消息,消息内容为dataStr,接收方IP地址为targetIP
if (socket != null) {
byte[] buffer = dataStr.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName(targetIP), 9527);
socket.send(packet);
}
}
}

2.3 UDP多播

UDP多播的实现类似群聊,需要先加入一个指定IP的群组,之后消息往该IP发送即可,,端口号任选,单播与多播端口号不可相同,保证发送方与接收方端口号一致且不与其他程序冲突即可,并且需要在2.1中展示的UDPManager类中增加MulticastSocket类型的成员变量、修改init方法和openReceiver方法、增加对应的多播方法,代码示例如下:

public class UDPManager {
//···
//多播地址自选,在224.0.1.0~238.255.255.255之间即可
public static final String MULICAST_ADDRESS = "224.255.0.1"
public MulticastSocket multiSocket;
public void init() {
try {
//先创建一个绑定了端口号为9527的DatagramSocket
socket = new DatagramSocket(9527);
//创建一个绑定端口号为9528的MulticastSocket
multiSocket = new MulticastSocket(9528);
//开启数据接收器
openReceiver();
//加入多播群组
multiSocket.joinGroup(InetAddress.getByName(MULICAST_ADDRESS))
//发送广播消息
sendBroadcast("Hello World!");
} catch (Exception e) {
e.printStackTrace();
}
}
public void openReceiver() {
//···
//新建子线程接收多播数据
new Thread(new Runnable() {
@override
public void run() {
byte[] buffer = new byte[BUFFER_SIZE];
DatagramPacket dp = new DatagramPacket(buffer, BUFFER_SIZE);
while(multiSocket != null) {
try {
multiSocket.receive(dp);
System.out.println(new String(buffer));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start;
}
//···
public void sendMultiple(String dataStr) throws IOException {
//发送多播消息,消息内容为dataStr
if (multiSocket != null) {
byte[] buffer = dataStr.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName(MULICAST_ADDRESS), 9528);
multiSocket.send(packet);
}
}
}

2.4 局域网通信基础构想

在上述三种UDP通信方式的实现过程中,发现广播方式并不能送达局域网中所有接收者,非同一网段下的接收者将无法收到广播消息,而单播及多播是可以做到跨网段的。

初步设想,仅使用多播方式,局域网通信流程大致如下:

  1. 用户程序启动,UDP初始化完成;

  2. 加入组播,发送用户上线消息,暴露本机信息(IP地址等);

  3. 接收到用户上线消息的接收方将该用户加入在线用户列表,并再发送一次本机的用户上线消息;

  4. 用户触发消息发送,消息中附带本机信息(IP地址等)与指定接收方IP地址或是用户名等(可以是数组,指定多个接收方);

  5. 接收方收到消息,判断此消息指定接收方中是否有本机,若有则处理该消息,否则丢弃;

  6. 用户关闭程序,发送用户下线消息;

  7. 接收到用户下线消息的接收方将该用户移除在线用户列表。

3. Android平台同一wifi环境下的尝试

3.1 UDP通信方式上的问题

在Android平台上初步尝试了UDP的各个通信方式,发现多播方式受到了极大的影响,经多方查证并多次尝试多播的使用,最后放弃了在Android平台上使用多播方式,如读者有兴趣可以尝试解决一下。

3.2 安卓wifi局域网通信基础构想

参考之前的构想,多播方式无法使用的情况下,广播结合单播的方式成为我的备用方案,大致流程如下:

  1. 用户程序启动,UDP初始化完成;

  2. 发送广播,传输用户上线消息,暴露本机信息(IP地址等);

  3. 接收到广播的接收方将该用户加入在线用户列表,并向该用户发送一次本机的用户上线消息;

  4. 用户触发消息发送,以单播的方式发送给指定接收方的IP地址,消息中附带本机信息(IP地址等);

  5. 接收方收到消息,处理该消息。

  6. 用户关闭程序,发送用户下线消息;

  7. 接收到用户下线消息的接收方将该用户移除在线用户列表。

版权声明
本文为[coder-ice]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/hwb04160011/p/13960502.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云