java基础--网络编程之UDP
笔记摘要:
本篇博客首先对网络通信要素和网络通讯中两种常见协议:UDP和TCP进行了介绍,另外对于UDP协议下实现通信的接收端和发送端,
并最终通过多线程的群聊服务端对UDP的学习进行了总结。
一、网络通讯要素
IP地址:InetAddress
网络中设备的标识
不易记忆,可用主机名
本地回环地址:127.0.0.1 主机名:localhost
端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0~65535,其中0~1024系统使用或保留端口
传输协议
通讯的规则
常见协议:TCP ,UDP
二、网络参考模型图
三、UDP与TCP特点
UDP
将数据及源和目的封装成数据包中,不需要建立连接
每个数据包的大小限制在64K内
因无连接,是不可靠协议
不需要建立连接,速度快
应用:聊天软件、视频会议、对话机
TCP
建立连接,形成传输数据的通道,对方必须存在
在连接中进行大量数据传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
应用:电话通信
四、Socket
Socket就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信
数据在两个Socket间通过传输。
五、UDP传输的使用
通过简单的UDP客户端与接收端学会如何创建一个UDP服务
udp发送端
需求:通过udp传输方式,将一段文字数据发送出去
思路:
1,建立updsocket服务。
2,提供数据,并将数据封装到数据包中。
3,通过socket服务的发送功能,将数据包发出去。
4,关闭资源。
简单的UDP发送端
import java.net.*; class UdpSend { public static void main(String[] args) throws Exception { //1,创建udp服务。通过DatagramSocket对象。 DatagramSocket ds = new DatagramSocket(8888); //2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port) byte[] buf = "udp ge men lai le ".getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),10000); //3,通过socket服务,将已有的数据包发送出去。通过send方法。 ds.send(dp); //4,关闭资源。 ds.close(); } }
简单的UDP接收端:用于接收udp协议传输的数据并处理
思路:
1,定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。
方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储接收到的字节数据。
因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
5,关闭资源。
简单的UDP接收端代码
class UdpRece { public static void main(String[] args) throws Exception { //1,创建udp socket,建立端点。 DatagramSocket ds = new DatagramSocket(10000); while(true) { //2,定义数据包。用于存储数据。 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); //3,通过服务的receive方法将收到数据存入数据包中。 ds.receive(dp);//阻塞式方法。 //4,通过数据包的方法获取其中的数据。 String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); int port = dp.getPort(); System.out.println(ip+"::"+data+"::"+port); } //5,关闭资源 //ds.close(); } }
五、使用键盘录入的UDP接收端和服务端
使用while实现循环发送和接收
import java.net.*; import java.io.*; class UdpS2 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(); //键盘录入 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while((line=bufr.readLine())!=null) { if("886".equals(line)) //当输入内容为“886”,键盘录入结束 break; byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("169.254.57.236"),10002); ds.send(dp); } ds.close(); } } class UdpR2 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(10002); while(true) { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); ds.receive(dp); String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); System.out.println(ip+"::"+data); } } }
广播的发送:
169.254.57.236 末尾如果是".0"网络段,".255"代表.网络段的广播地址,该网络段所有开启接收端的机器都能收到信息。
六、简单的多线程的群聊软件
需求:接收和发送在一个进程中执行
思路:
有收数据的部分,和发数据的部分。这两部分需要同时执行,那就需要用到多线程技术。
一个线程控制收,一个线程控制发。
因为收和发动作是不一致的,所以要定义两个run方法,而且这两个方法要封装到不同的类中。
模拟聊天室效果:
运行该聊天室,可以接收其他窗口发送过来的数据,也可以向其他用户发送数据,为了模拟聊天的效果,所以我们另外开一些窗口,
这些窗口只需开启一个发送端即可,所有窗口发送的数据最终会显示在聊天室窗口上。
多线程群聊实现代码
import java.io.*; import java.net.*; class ChatDemo { public static void main(String[] args) throws Exception { DatagramSocket sendSocket = new DatagramSocket(); DatagramSocket receSocket = new DatagramSocket(10002); new Thread(new Send(sendSocket)).start(); new Thread(new Rece(receSocket)).start(); } } class Send implements Runnable { private DatagramSocket ds; public Send(DatagramSocket ds) { this.ds = ds; } public void run() { try { BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while((line=bufr.readLine())!=null) { byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("169.254.26.235"),10002); ds.send(dp); if("886".equals(line)) break; } } catch (Exception e) { throw new RuntimeException("发送端失败"); } } } class Rece implements Runnable { private DatagramSocket ds; public Rece(DatagramSocket ds) { this.ds = ds; } public void run() { try { while(true) { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); ds.receive(dp); String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); if("886".equals(data)) { System.out.println(ip+"....离开聊天室"); break; } System.out.println(ip+":"+data); } } catch (Exception e) { throw new RuntimeException("接收端失败"); } } }