Java Socket 通信(二)

mac2024-04-02  36

文章目录

1. 前言2. DatagramSocket 类2.1 构造DatagramSocket2.2 DatagramSocket 类的常用方法2.2.1 发送数据2.2.2 接收数据2.2.3 建立固定通信关系2.2.4 解除固定通信关系2.2.5 关闭 DatagramSocket 2.3 设置 DatagramSocket 的选项 3. DatagramPacket 类3.1 DatagramPacket 类的构造方法3.2 DatagramPacket 类的常用方法3.2.1 查询 DatagramPacket3.2.2 设置 DatagramPacket 4. 程序实例4.1 UDPService4.2 UDPClient4.3 运行截图 5. 组播Socket5.1 MulticastSocket类5.2 构造 MulticastSocket5.3 MulticastSocket 的常用方法5.3.1 加入组播组5.3.2 离开组播组5.3.3 设置网络接口5.3.4 查询网络接口 6. 程序实例6.1 MulticastSender6.2 MulticastReceiver6.3 运行截图

1. 前言

基于传输层协议的UDP的网络通信是不可靠的、无序的、无差错控制的。使用DatagramSocket类表示UDP通信节点的套接字,使用DatagramPacket表示节点之间发送和接收的数据报。基于UDP通信的节点之间不需要建立任何连接。组播也是一种基于UDP的通信。

2. DatagramSocket 类

每个DatagramSocket对象会绑定本地IP地址和一个UDP端口号,它可以和任意其他DatagramSocket对象之间有通信行为,但不会建立实时的网络连接。

2.1 构造DatagramSocket

DatagramSocket():创建一个DatagramSocket对象,但没有设置绑定的端口号,相当于绑定了本地的任意一个可用的端口DatagramSocket(int port):创建一个DatagramSocket对象,并绑定本地端口号port。DatagramSocket(int port,InetAddress addr):创建一个DatagramSocket对象,并绑定本地地址addr和端口号port。IP地址为网络接口地址,如果设置为0.0.0.0,就是通配地址DatagramSocket(SocketAddress bindaddr):创建一个DatagramSocket对象,并绑定套接字地址bindaddrvoid bind(SocketAddress addr):如果使用无参数构造方法创建一个DatagramSocket对象,可以进行一些选项的设置,之后使用bind方法绑定IP地址和端口

2.2 DatagramSocket 类的常用方法

2.2.1 发送数据

DatagramSocket的send方法负责发送一个数据报,该方法的定义:void send(DatagramPacket p),其中参数p包含要发送的数据、数据长度、目的IP地址和端口。

//1234本地端口号 DatagramSocket ds = new DatagramSocket(1234); InetAddress receiver = InetAddress.getLocalHost(); byte[] b = "send a message".getBytes(); //5678目的端口号 DatagramPacket dp = new DatagramPacket(b, b.length, receiver, 5678); ds.send(dp)

2.2.2 接收数据

void receive(DatagramPacket p): DatagramSocket类的receive方法用于接收消息。消息并不是以返回值的形式得到的,而是存在于p缓冲区中,p中还包括发送者的IP地址和端口信息。 receive方法是一个阻塞的方法,调用receive的时候,如果没有收到数据报会一直阻塞,直到收到一个数据报。

byte[] b = new byte[100]; DatagramPacket dp = new DatagramPacket(b,100); DatagramSocket ds = new DatagramSocket(1234); ds.receive(dp);

2.2.3 建立固定通信关系

UDP的节点之间是不建立实时连接的,但是却可以建立这样一种固定关系:一个节点的DatagramSocket,只能同另一个固定的节点(由IP地址和端口号确定)进行通信

DatagramSocket ds = new DatagramSocket(); ds.connect(InetSocketAddress.createUnresolved("www.foo.com",1234));

2.2.4 解除固定通信关系

DatagramSocket ds = new DatagramSocket(1234); ... ds.disconnect();

2.2.5 关闭 DatagramSocket

void close():关闭,并释放所有相关的资源。

... ds.close();

补充:

isBound(): 判断DatagramSocket对象的绑定状态isConnected():判断DatagramSocket对象是否处于固定通信连接状态isClosed():判断DatagramSocket对象是否关闭

2.3 设置 DatagramSocket 的选项

选项含义SO_BROADCAST广播地址SO_TIMEOUT设定接收数据报的等待超时时间SO_RECBUF表示接收数据缓冲区的大小SO_REUSEADDR表示是否允许重用DatagramSocket所绑定的本地地址

3. DatagramPacket 类

3.1 DatagramPacket 类的构造方法

发送数据的DatagramPacket对象 DatagramPacket(byte[] buf, int length, InetAddress address, int port):用于发送的DatagramPacket对象,包括目的节点的IP地址address和端口号port。DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):设置了发送数据的起始位置为:data[offset]DatagramPacket(byte[] buf, int offset, int length, SocketAddress address):将目的地址和端口号合并在了一起DatagramPacket(byte[] buf, int length, SocketAddress address) 接收数据的DatagramPacket对象 DatagramPacket(byte[] buf, int length):用于接收数据,只需设置接收缓冲区buf,并指定读取的字节数lengthDatagramPacket(byte[] buf, int offset, int length):设置了接收缓冲区buf的起始位置偏移量

3.2 DatagramPacket 类的常用方法

3.2.1 查询 DatagramPacket

InetAddress getAddress():对于发送数据报,返回目的节点的主机IP地址。对于接收数据报,返回的是数据的来源主机IP地址。总之,返回的是远程主机的IP地址int getPort():返回的是远程主机的UDP端口号。byte[] getData():对于发送数据报,返回的是发送缓冲区从offset开始的数据,对于接收数据,返回的是接收缓冲区的数据。int getOffset():返回的是发送或者接收缓冲区的数据偏移量offsetint getLength():返回的是发送或者接收缓冲区中数据的长度SocketAddress getSocketAddress():返回的是远程主机IP地址和UDP端口号

3.2.2 设置 DatagramPacket

void setData(byte[] buf):设置数据报的缓冲区数据void setData(byte[] data, int offset, int length):数据从buf[offset]开始,长度为lengthvoid setAddress(InetAddress iaddr):发送数据报时,使用参数iaddr设置目的主机的IP地址void setPort(int iport):发送数据报时,使用参数iport设置目的主机的UDP端口号。void setSocketAddress(SocketAddress address):发送数据报时,使用参数iaddr设置目的主机的套接字地址void setLength(int length):设置数据报的长度

4. 程序实例

4.1 UDPService

package udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.text.SimpleDateFormat; import java.util.Date; public class UDPService { DatagramSocket ds = null; public UDPService() throws Exception{ ds = new DatagramSocket(5678); System.out.println("服务启动"); } public void service(){ new Thread(){ public void run(){ while(true){ try { byte[] b = new byte[100]; DatagramPacket dp = new DatagramPacket(b, b.length); ds.receive(dp); String msg = new String(b, 0, dp.getLength()); System.out.println("从" + dp.getAddress() + ":" + dp.getPort() + "收到:" + msg); if(msg.equalsIgnoreCase("date")){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy年mm月dd日"); dp.setData(("date:" + sdf.format(new Date())).getBytes()); }else if(msg.equalsIgnoreCase("time")){ SimpleDateFormat sdf = new SimpleDateFormat("HH:MM:SS"); dp.setData(("time:"+ sdf.format(new Date())).getBytes()); } ds.send(dp); } catch (IOException e) { e.printStackTrace(); } } } }.start(); } public static void main(String[] args) throws Exception { new UDPService().service(); } }

4.2 UDPClient

package udp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.*; public class UDPClient { public static void main(String[] args) { try { InetAddress server = InetAddress.getByName("localhost"); DatagramSocket ds = new DatagramSocket(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String msg = null; while((msg = br.readLine())!= null){ byte[] b = msg.getBytes(); DatagramPacket dp = new DatagramPacket(b, b.length, server, 5678); ds.send(dp); DatagramPacket sp = new DatagramPacket(new byte[100], 100); ds.receive(sp); msg = new String(sp.getData(),0, sp.getLength()); if(msg.equalsIgnoreCase("bye")){ break; } System.out.println("服务器:" + msg); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { } } }

4.3 运行截图

5. 组播Socket

组播也叫多播,组播组内的所有主机共享同一个D类IP地址,这种地址称为组播地址。一台主机可以自由决定何时加入或离开一个组播组。组播地址是范围在244.0.0.0~239.255.255.255之间的IP地址

5.1 MulticastSocket类

MulticastSocket类实际上是DatagramSocket类的子类,包含了DatagramSocket类的所有域和方法,还额外定义了与组播有关的一些方法。

5.2 构造 MulticastSocket

MulticastSocket():创建MulticastSocket对象MulticastSocket(int port):创建绑定到端口port的MulticastSocket对象MulticastSocket(SocketAddress bindAddress):创建绑定到端口套接字地址bindAddress的MulticastSocket对象。

5.3 MulticastSocket 的常用方法

5.3.1 加入组播组

void joinGroup(InetAddress mcastaddr) 其中mcastaddr是D类组播IP地址,如果要接收发送到组播组的数据,就必须要加入组播组void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) 其中netIf参数设置了使用哪个网络接口加入到组播组

5.3.2 离开组播组

void leaveGroup(InetAddress mcastaddr) 其中,mcastaddr是D类组播IP地址,调用leaveGroup之前,MulticastSocket对象应该已经加入了某个组播组。void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) 其中netIf设置了哪个网络接口离开组播组。

5.3.3 设置网络接口

void setInterface(InetAddress inf) 假设主机有多个网络接口,通过该方法设置究竟是哪一个接口参与组播操作。

5.3.4 查询网络接口

InetAddress getInterface() 此方法返回用于组播的网路接口地址

6. 程序实例

6.1 MulticastSender

package udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.UnknownHostException; public class MulticastSender { public static void main(String[] args) throws IOException { InetAddress group = InetAddress.getByName("226.0.0.1"); MulticastSocket ms = new MulticastSocket(); ms.joinGroup(group); String msg = "Hello, everybody!"; byte[] b = msg.getBytes(); DatagramPacket dp = new DatagramPacket(b, b.length, group, 5678); ms.send(dp); System.out.println("发送问候给:"+ group + ":" + 5678); ms.close(); } }

6.2 MulticastReceiver

package udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class MulticastReceiver { public static void main(String[] args) throws IOException { InetAddress group = InetAddress.getByName("226.0.0.1"); MulticastSocket ms = new MulticastSocket(5678); ms.joinGroup(group); byte[] b = new byte[100]; DatagramPacket dp = new DatagramPacket(b, b.length); ms.receive(dp); String str = new String(dp.getData(), 0, dp.getLength()); System.out.println("从" + dp.getAddress().toString() + ":"+dp.getPort()+"收到消息"); System.out.println(str); ms.leaveGroup(group); ms.close(); } }

6.3 运行截图

最新回复(0)