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

在网上看了几个udp编程的实例,都是实现简易聊天室,但是都存在一个问题,就是通信的一方不能实现连续的发送或者是连续的接受消息,因为发送消息,键盘的读入Scanner会导致阻塞,同理,接受消息的时候,socket.receive()方法也会导致阻塞。
基于这个原因,我们如果把通信中一方的发送功能和接受功能用同一个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地址,目的端口号。约定发送”再见“后,退出聊天,关闭socket资源,这里因为通信一方有发送,接收两个线程,要声明一个共享变量isOffline,同步多线程间的动作。
接收线程如下:

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;
            }
        }
    }
}

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

    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“改为广播地址即可。
调出命令行输入ipconfig,查看自己的ipv4地址和子网掩码,将主机地址改为全1,即可得到广播地址啦!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值