Java 网络编程之UDP通信和简单的群聊程序

UDP通信需要明确的几点:

UDP通信不是面向连接的,发送端不管接收端是否启动是否能接收,发完数据报就结束。

无论是发送端还是接收端,都需要描述两个对象:套接字和数据报。

接收端的套接字对象中必须明确接收端口,且必须和发送端指定的目标端口一致。而发送端的套接字中则一般采用随机分配的发送端口。

无论是发送端还是接收端,数据报中都记录了自己和对方的socket信息(ip+port),还提供了用于发送或接收的数据缓冲区。这些数据只有数据报对象自己最清楚,如getPort(),getAddress(),getData()等。

(1).只不过对于发送端来说,创建发送报文对象需要指定目标套接字信息(ip+port),还需明确数据发送缓冲区。

(2).而对于接收端来说,则只需明确一个数据接收缓冲区即可。

接收端应该不断循环地负责接收。

UDP套接字类DatagramSocket,UDP数据报类DatagramPacket。

UDPSender端:

import Java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; public class UDPSender { public static void main(String[] args) { DatagramSocket dgs = null; try { // 1. 创建udp发送端的socket,一般使用随机发送端口 dgs = new DatagramSocket(); // 2. 创建udp报文包对象 // 2.1 创建数据发送缓冲区 String text = "Hello World! I'm coming"; byte[] buf = text.getBytes(); // 2.2 创建发送数据报文对象 InetSocketAddress isa = new InetSocketAddress("192.168.0.124",8888); DatagramPacket dgp = new DatagramPacket(buf,buf.length,isa); //DatagramPacket dgp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.0.124"), 8888); // 3.发送udp报文 dgs.send(dgp); } catch (SocketException e1) { e1.printStackTrace(); } catch (UnknownHostException e2) { e2.printStackTrace(); } catch (IOException e3) { e3.printStackTrace(); } finally { // 4. 关闭套接字 dgs.close(); } } }

UDPRecver端:

import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPRecver { public static void main(String[] args) { while(true){ // 1.创建udp接收套接字,接收端必须指定正确的端口 DatagramSocket dgs = null; try { dgs = new DatagramSocket(8888); // 2. 创建udp接收数据包对象 byte[] buf = new byte[1024]; DatagramPacket dgp = new DatagramPacket(buf, buf.length); // 3.从套接字中接收数据到数据包中 dgs.receive(dgp); // 4.展示udp发送端相关信息,包括发送的数据 String data = new String(dgp.getData(), 0, dgp.getLength()); String ip = dgp.getAddress().getHostAddress(); int port = dgp.getPort(); System.out.println("Data: "+data+" ip: "+ip+" port: "+port); } catch (SocketException s) { s.printStackTrace(); } catch (IOException i) { i.printStackTrace(); } finally { dgs.close(); } } } }

UDP实现群聊:

思路:

一个线程负责发,一个线程负责收,因此使用多线程。

发送端的数据报目标端应该指定为广播目标。且发送的数据来源于键盘输入。

接收端要无限循环接收数据,但应该提供下线离开功能。(假设收到了"bye",就表示下线)

import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class QunChat { public static void main(String[] args) throws SocketException { //发送端和接收端套接字,接收端套接字端口为8888,需要传递给发送端的报文对象 DatagramSocket send_socket = new DatagramSocket(); DatagramSocket recv_socket = new DatagramSocket(8888); Sender sender = new Sender(send_socket,8888); Recver recver = new Recver(recv_socket); Thread send_thread1 = new Thread(sender); Thread recv_thread1 = new Thread(recver); send_thread1.start(); recv_thread1.start(); } } class Sender implements Runnable { private DatagramSocket send_sock; private int dest_port; Sender(DatagramSocket s,int port){ //初始化时就指定目标端口 this.send_sock = s; this.dest_port = port; } public void run() { while(true) { try { //群聊发送目标,以广播为例 InetSocketAddress isa = new InetSocketAddress("192.168.0.255", dest_port); //从键盘接收数据 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line; while((line=bufr.readLine())!=null) { //如果发送的是bye,则断开,且不发送给接收端 if(line.equals("bye")) break; byte[] buf = line.getBytes(); DatagramPacket dp = new DatagramPacket(buf,buf.length, isa); send_sock.send(dp); } } catch (IOException e) { e.printStackTrace(); } finally { send_sock.close(); } } } } class Recver implements Runnable { private DatagramSocket recv_sock; Recver(DatagramSocket socket){ this.recv_sock = socket; } public void run() { while(true) { try { //接收报文对象 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); recv_sock.receive(dp); String src_ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); if(data.equals("bye")) System.out.println(src_ip +" leaving");; System.out.println("Recviving data: "+ data+" from "+src_ip ); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/67d327195516b502b17dc5c4c864b859.html