风也温柔

计算机科学知识库

java实现聊天室功能 基于JAVA的udp编程实现简易聊天室

  在网上看了几个udp编程的实例,都是实现简易聊天室,但是都存在一个问题,就是通信的一方不能实现连续的发送或者是连续的接受消息java实现聊天室功能,因为发送消息,键盘的读入会导致阻塞,同理,接受消息的时候java实现聊天室功能 基于JAVA的udp编程实现简易聊天室,.()方法也会导致阻塞。

  基于这个原因,我们如果把通信中一方的发送功能和接受功能用同一个main线程实现,就只能按照,发一条,收一条,这个顺序聊天,如果想解决阻塞的缺点,只能用多线程来实现。

  首先,将发送数据的功能封装成函数,形参列表分别为数据报套接字,目标IP,目标端口,代码如下:

   public static String sendData(DatagramSocket socket,String destAddress,int destPort) throws IOException {

            Scanner in = new Scanner(System.in);
            String data;
            InetAddress address = InetAddress.getByName(destAddress);
    //        将键盘接受到的字符转为字节数组
            data = in.nextLine();
            byte[] buf = data.getBytes();
    //            将接受的数据封装为数据报包进行发送
    //            在环回IP地址内测试,指定接收端口号为destPort
            DatagramPacket senderPacket = new DatagramPacket(buf, 0,buf.length,address, destPort);
            socket.send(senderPacket);
            return data;
        }

  将接受数据的功能封装为函数,形参列表为数据报套接字,这里我们要注意,实现多线程的时候,要确保发送线程和接受线程绑定的是同一个套接字,这样才能共用一个端口号,套接字对象以构造方法的形式传入。接收数据的方法如下:

   public static String receiveData(DatagramSocket socket) throws IOException {

            byte[] receiverBuf = new byte[1024];
            DatagramPacket receiverPacket = new DatagramPacket(receiverBuf,0,receiverBuf.length);
            socket.receive(receiverPacket);
            String message = new String(receiverPacket.getData(), receiverPacket.getOffset(), receiverPacket.getLength());
            System.out.println(receiverPacket.getAddress() + "/" + receiverPacket.getPort() + "说: " + message);
            return message;
        }

  继续实现两个多线程接口,基于以上两个方法。代码如下:

   class SendTask implements Runnable {

        private DatagramSocket socket;
        private int destPort;
        private String destAddress;
        public SendTask(DatagramSocket socket,int destPort,String destAddress) {
            this.socket = socket;
            this.destAddress = destAddress;
            this.destPort = destPort;
        }
        @Override
        public void run() {
            try {
                String message = null;
                while (true) {
                    message = OnePerson.sendData(socket,destAddress,destPort);
                    if ("再见".equals(message)) {
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                synchronized (OnePerson.lock) {
                    if (OnePerson.isOffline) {
                        socket.close();
                    }
                }
            }
        }
    }

  发送线程的构造方法传入了数据报套接字,目的IP地址,目的端口号。约定发送”再见“后,退出聊天,关闭资源,这里因为通信一方有发送,接收两个线程,要声明一个共享变量,同步多线程间的动作。

  接收线程如下:

   class ReceiveTask implements Runnable {

        private DatagramSocket socket;
        public ReceiveTask(DatagramSocket socket) {
            this.socket = socket;
        }
        @Override
        public void run() {
            try {
                String message;
                while (true) {
                    message = OnePerson.receiveData(socket);
                    if ("再见".equals(message)) {
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                synchronized (OnePerson.lock) {
                    OnePerson.isOffline = true;
                }
            }
        }
    }

  主方法声明套接字对象java实现聊天室功能,启动多线程,指定自己的发送端口,指定通信对方的接收端口,通信另一方的发送端口 == 自己的接收端口,所以我们双方通信只需两个端口即可完成,如果没有实现套接字对象的绑定,就要用四个端口来实现,这个留给读者自己完成吧!

  主方法如下:

   public static void main(String[] args) throws IOException {

            DatagramSocket socket = new DatagramSocket(10000);
            String destAddress = "127.0.0.1";
            int destPort = 10001;
            Thread t1 = new Thread(new SendTask(socket,destPort,destAddress),"发送线程");
            Thread t2 = new Thread(new ReceiveTask(socket),"接受线程");
            t1.start();
            t2.start();
        }

  通信另一方只需要将端口号互换 即可完成通信了。

  如果我们想和小伙伴通信的话,将测试的本地环回IP地址”127.0.0.1“改为广播地址即可。

  调出命令行输入,查看自己的ipv4地址和子网掩码,将主机地址改为全1,即可得到广播地址啦!

  文章来源:https://blog.csdn.net/qq_43128621/article/details/109325498