zoukankan      html  css  js  c++  java
  • java 网络编程之UDP通信和简单的群聊程序

    UDP通信需要明确的几点:

    1. UDP通信不是面向连接的,发送端不管接收端是否启动是否能接收,发完数据报就结束。
    2. 无论是发送端还是接收端,都需要描述两个对象:套接字和数据报。
    3. 接收端的套接字对象中必须明确接收端口,且必须和发送端指定的目标端口一致。而发送端的套接字中则一般采用随机分配的发送端口。
    4. 无论是发送端还是接收端,数据报中都记录了自己和对方的socket信息(ip+port),还提供了用于发送或接收的数据缓冲区。这些数据只有数据报对象自己最清楚,如getPort(),getAddress(),getData()等。
      • (1).只不过对于发送端来说,创建发送报文对象需要指定目标套接字信息(ip+port),还需明确数据发送缓冲区。
      • (2).而对于接收端来说,则只需明确一个数据接收缓冲区即可。
    5. 接收端应该不断循环地负责接收。
    6. 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实现群聊:

    思路:

    1. 一个线程负责发,一个线程负责收,因此使用多线程。
    2. 发送端的数据报目标端应该指定为广播目标。且发送的数据来源于键盘输入。
    3. 接收端要无限循环接收数据,但应该提供下线离开功能。(假设收到了"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();
                }
            }
        }
    }
    

    注:若您觉得这篇文章还不错请点击右下角推荐,您的支持能激发作者更大的写作热情,非常感谢!

  • 相关阅读:
    [技术项目4]--接口自动化数据一览项目总结
    [技术项目3]--流量回放项目总结
    [技术项目2]--禅道项目报告统计总结
    [技术项目1]--数据工厂项目总结
    自动化测试常用的框架
    【vue】element-表单中,下拉框选中某个值后,同步更新其他输入框的值
    【vue】vue打包后,将dist文件夹自动压缩成生成dist.zip压缩包--filemanager-webpack-plugin
    译文:ovs+dpdk中的“vHost User NUMA感知”特性
    vue中防抖,节流的使用
    横向结构的树组件(leader-line-vue)
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/8245476.html
Copyright © 2011-2022 走看看