【网络编程】 开发一个基于UDP协议的网络聊天室。(不使用广播实现)

开发一个基于UDP协议的网络聊天室。

提示:

不使用广播实现。

客户端的接收消息和发送消息分别使用一个线程。

服务器端可不使用线程,维护一个ArrayList列表用来存储客户端的地址,当服务器端接收到消息后,先提取客户端的地址,和列表中存储的地址比较是否存在,如果存在,则接收消息后转发给列表中所有的客户端地址,如果不存在,则把该客户端地址提取出来保存在列表中,并接收消息转发给列表中的所有客户端地址。

基于UDP协议的网络编程通信原理和TCP协议不同,基于TCP协议的通信是客户端和服务器端建立连接管道,这个管道就像一个输出输出流,发送消息使用输出流,接收消息使用输入流;基于UDP协议的通信不建立连接,一端向另一端发送消息需要创建数据报,数据报中包含目标地址和要发送的内容。

服务器端收到后,提取出内容和客户端的地址,把消息再发回给客户端。
客户端代码中 finalSocket 与 finalSocket1 去接收socket, 而不是重新构造数据报套接字,是为了系统分配的端口一致,以便服务器能根据该端口发送接收信息给该客户端地址

客户端代码

package com.fan.udp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * @Author: Travelmate
 * @CreateTime: 2021/3/12 19:08
 * @Description: 客户端
 */
// finalSocket  与 finalSocket1 去接收socket, 而不是重新构造数据报套接字,是为了系统分配的端口一致,以便服务器能根据该端口发送接收信息给该客户端地址

public class UdpClient {
    
    



    public static void main(String[] args) {
    
    
        //调用构造方法
        new UdpClient();
    }

    public UdpClient(){
    
    

        DatagramSocket socket = null;
        try {
    
    
            //端口使用系统分配的端口
            socket = new DatagramSocket();
            //
            DatagramSocket finalSocket = socket;
            //发送信息到服务器
            new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    String userInput;
                    //接收键盘输入
                    BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
                    try {
    
    
                        System.out.println("请输入用户名字: ");
                        String username = stdIn.readLine();
                        //服务器端地址
                        InetAddress ip = InetAddress.getByName("127.0.0.1");
                        //字节数组 存储发送内容
                        byte[] bytes = null;
                        DatagramPacket packet = null;
                        while ((userInput = stdIn.readLine())!=null){
    
    
                            bytes = (username + " : " + userInput).getBytes();
                            //服务器的目的地址,端口号,构造数据报
                            packet = new DatagramPacket(bytes, bytes.length, ip, 9999);
                            //发送数据报
                            finalSocket.send(packet);
                        }
                    } catch (SocketException e) {
    
    
                        e.printStackTrace();
                    } catch (IOException e) {
    
    
                        e.printStackTrace();
                        if (finalSocket != null){
    
    
                            finalSocket.close();
                        }
                    }
                }
            }).start();


            DatagramSocket finalSocket1 = socket;
            //接收服务器传来的信息
            new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    DatagramPacket packet = null;
                    try {
    
    
                        byte[] bytes = new byte[1024];
                        while (true){
    
    
                            packet = new DatagramPacket(bytes, bytes.length);
                            finalSocket1.receive(packet);
                            String receiveStr = new String(packet.getData(), 0 , packet.getLength());
                            System.out.println(receiveStr);
                        }
                    } catch (SocketException e) {
    
    
                        e.printStackTrace();
                    } catch (IOException e) {
    
    
                        e.printStackTrace();
                        if (finalSocket1 != null){
    
    
                            finalSocket1.close();
                        }
                    }


                }
            }).start();
        } catch (SocketException e) {
    
    
            e.printStackTrace();
        }


    }
}

服务端代码

package com.fan.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;

/**
 * @Author: Travelmate
 * @CreateTime: 2021/3/12 19:08
 * @Description: 服务器端
 */
public class UdpServer {
    
    

    public static void main(String[] args) {
    
    
        DatagramSocket socket = null;
        DatagramPacket packet = null;

        //用来存储客户端的地址 我这里用(ip+端口号)
        ArrayList<String> arrayList = new ArrayList<>();
        String receive;
        try {
    
    
            //绑定端口9999,构造数据报
            socket = new DatagramSocket(9999);
            while (true){
    
    
                byte[] buf = new byte[1024];
                packet = new DatagramPacket(buf,buf.length);
                //接收数据报
                socket.receive(packet);
                //提取客户端的地址 ip + 端口号
                InetAddress inetAddress = packet.getAddress();
                int port = packet.getPort();
                //如果不存在 , 就加入
                if (!arrayList.contains(inetAddress + ":" + port)){
    
    
                    arrayList.add(inetAddress + ":" + port);
                }
                receive = new String(packet.getData(), 0 , packet.getLength());
                System.out.println(receive + "  来自:" + inetAddress + ":" + port);
                byte[] bytes = new byte[1024];
                bytes = ("来自客户端线程" + inetAddress + ":" + port + "的信息: " + receive).getBytes();
                // 接收消息转发给列表中的所有客户端地址。
                for (String s : arrayList){
    
    
                    // 去掉地址最前面的 / 字符
                    String str1 = s.substring(1);
                    String[] str = str1.split(":");
                    InetAddress ip = InetAddress.getByName(str[0]);
                    int port1 = Integer.parseInt(str[1]);
                    packet = new DatagramPacket(bytes, bytes.length , ip, port1);
                    socket.send(packet);
                }
            }

        } catch (SocketException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            if (socket != null){
    
    
                socket.close();
            }
        }
    }
}

开启服务端和两个客户端 截图

服务端(接收所有客户端发送的信息)
在这里插入图片描述
客户端1(发送信息,接收服务端收到的所有信息记录)
在这里插入图片描述
客户端2(发送信息,接收服务端收到的所有信息记录)
在这里插入图片描述

おすすめ

転載: blog.csdn.net/weixin_44695700/article/details/114715414