Java网络编程实现一(服务器)对多(客户端)

本文展示了如何使用Java的BIO模型,通过多线程技术和网络编程实现一个服务器同时处理多个客户端连接。服务器端创建线程接收客户端连接,并为每个连接创建单独的线程进行数据交互。客户端也采用双线程模型,一个接收服务器数据,一个发送数据。当客户端断开或服务器退出时,会进行相应的通知和资源清理。

使用多线程+网络编程实现一个服务器对多个客户端

在该程序中用到的知识点

  1. java的BIO
  2. ServerSocket和Socket 网络编程
  3. 多线程的知识(个人认为重要)

实现的思路

服务器端(使用多个线程)

  1. 在客户端需要有一个集合来存储已经连接上的客户端, 如果客户端断开连接则需要从集合中删除
  2. 创建一个线程来处理客户端的连接
  3. 每一个客户端的连接都需要一个线程来接收客户端的请求
  4. 使用主线程来给客户端发送数据(轮询客户端集合中的Socket给客户端发送数据)

客户端(使用两个线程)

  1. 首先创建一个线程来接收服务器端的数据
  2. 使用主线程来给服务器端发送数据

效果的演示

  1. 启动服务器端

在这里插入图片描述

  1. 启动客户端
    在这里插入图片描述

    启动客户端后,服务器端可以监听到连接

在这里插入图片描述

  1. 在客户端中发送数据在服务端可以接收到

在这里插入图片描述
在这里插入图片描述

4、 在服务器端发送数据,在已经连接上的客户端中可以接受到消息
在这里插入图片描述
在这里插入图片描述

  1. 客户端退出,服务器端有提示
    在这里插入图片描述

  2. 服务器端退出,所有的客户端有提示,并且客户端全部断开连接
    在这里插入图片描述

代码演示

服务器端

public class Server {

    public static void main(String[] args) {
        List<Socket> socketList = new ArrayList<>();

        // 开启线程接收客户端的连接
        new Thread(new AcceptSocket(socketList)).start();

        while (true) {
            Scanner scanner = new Scanner(System.in);
            String sendInfo = scanner.nextLine();
            // 循环向所有的客户端发送消息
            socketList.forEach(socket -> {
                try {
                    PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
                    printWriter.println(sendInfo);
                    printWriter.flush();
                } catch (SocketException e) {
                    System.out.println(1);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

// 接收客户端Socket线程
class AcceptSocket implements Runnable {

    List<Socket> socketList;

    public AcceptSocket(List<Socket> socketList) {
        this.socketList = socketList;
    }

    @Override
    public void run() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(9000);
            System.out.println("监听客户端的连接");
            // 循环接收客户端的请求
            while (true) {
                Socket socket = serverSocket.accept();
                // 接收到后加入到 socketList
                socketList.add(socket);
                // 开启处理客户端线程
                new Thread(new HandleSocket(socket, socketList)).start();
            }
        } catch (SocketException e) {
            System.out.println(2);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接
            try {
                if (null != serverSocket) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

// 处理客户端Socket线程
class HandleSocket implements Runnable {

    Socket socket;

    List<Socket> socketList;

    public HandleSocket(Socket socket, List<Socket> socketList) {
        this.socket = socket;
        this.socketList = socketList;
    }

    @Override
    public void run() {
        BufferedReader bufferedReader = null;
        try {
            // 读取客户端发来的数据
            bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("等待读取客户端:" + socket.getLocalAddress().toString().substring(1) + ":" + socket.getPort() + " 的消息");
            while (true) {
                String clientInfo = bufferedReader.readLine();
                System.out.println(socket.getLocalAddress().toString().substring(1) + ":" + socket.getPort() + "发送的消息是:" + clientInfo);
            }
        } catch (SocketException e) {
            // 强制关闭连接后的处理
            System.out.println(socket.getLocalAddress().toString().substring(1) + ":" + socket.getPort() + "断开连接");
            // 将该连接从socketList中移除
            socketList.remove(socket);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            // 关闭连接
            try {
                if (null != bufferedReader) {
                    bufferedReader.close();
                }
                if (null != socket) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Socket socket = null;
        PrintWriter printWriter = null;
        try {
            socket = new Socket("localhost", 9000);
            printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));

            //开启线程接收服务端的消息
            new Thread(new AcceptServer(socket)).start();
            System.out.println("可以给服务器端发送数据了");
            while (true) {
                // 给服务端发送消息
                String sendInfo = scanner.nextLine();
                printWriter.println(sendInfo);
                printWriter.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接
            try {
                if (null != socket) {
                    socket.close();
                }
                if (null != printWriter) {
                    printWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

class AcceptServer implements Runnable {

    Socket socket;

    public AcceptServer(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (true) {
                String serverInfo = bufferedReader.readLine();
                System.out.println("服务器的消息为:" + serverInfo);
            }
        } catch (SocketException e) {
            System.out.println("服务器异常关闭");
            // 退出
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接
            try {
                if (null != bufferedReader) {
                    bufferedReader.close();
                }
                if (null != socket) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

库里的球衣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值