java 服务器在新客户端加入时放弃旧客户端

java server gives up on older clients whenever a new one joins

首先我想介绍一下我现在的代码:

/**
 App.java:
**/
package org.example;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;


public class App 
{
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(2343);
        } catch (IOException e) {
            System.err.println("Could not listen on 2343");
        }

        try {
            while (true) {
                Socket clientSocket = serverSocket.accept();
                try {
                    new Helper(clientSocket);
                } catch (IOException e) {
                    clientSocket.close();
                }
            }
        } finally {
            serverSocket.close();
        }
    }
}


/**
 Helper.java:
**/
package org.example;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class Helper extends Thread {

    public static BufferedReader br;
    public static BufferedWriter bw;
    public static String output = "";

    public Helper(Socket socket) throws IOException {
        System.out.println("user found");
        br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
        start();
    }
    @Override
    public void run() {
        while (true) {
            try {
                bw.write("set");
                bw.newLine();
                bw.flush();
                System.out.println(br.readLine()+"\n"+getId());
            } catch (IOException e) {
                System.out.println("Client Lost");
                break;
            }
        }
    }
}


/**
 Cli.java
**/
package org.example2;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;

class Cli {
    public static void main(String[] argv) throws Exception {
        BufferedWriter bw;
        Socket clientSocket;

        BufferedReader br;
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));


        clientSocket = new Socket("laith.com.au", 2343);
        bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8));
        br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
        while(true){
            String input=br.readLine();
            bw.write(inFromUser.readLine());
            bw.newLine();
            bw.flush();
        }
    }
}

其次我将展示输出:

App.java

user found
hello world
13
hello world
13
user found
hello world
14
hello world
14
hello world
13
Client Lost
Client Lost

Cli.java(no1 所有用户输入)

hello world
hello world
hello world
hello world

Cli.java(no2 所有用户输入)

hello world
hello world

成绩单:

我启动应用程序:

我启动 Cli 的第一个实例:user found

我在 CLI 1 中输入“hello world”:hello world(换行符)13

我再次在 Cli 1 中输入“hello world”:hello world(换行符)13

我启动 Cli 的第二个实例:user found

我在 CLI 2 中输入“hello world”:hello world(换行符)14

我再次在 Cli 2 中输入“hello world”:hello world(换行符)14

我在 CLI 中输入“hello world”no1hello world(换行符)13

我再次在 CLI 1 中输入“hello world”:

我终止 Cli no1:

我终止 Cli no2:Client Lost(换行符)Client Lost

最后的问题:

怎么会,每当我添加另一个客户端连接到服务器时,旧客户端只能在服务器停止响应之前再发送一条消息。

那是因为 Helper class 中的 brbw 声明为 static.

static 表示该字段由 class.

的所有实例共享

因此,当为您的第二个客户端创建第二个 Helper 实例时,这些共享的 brbw 会被 reader 覆盖,并为此编写新连接 => 即之后 Helper 个线程读取和写入这个新连接。

您看到旧客户端又写了一个,因为当 brbw 被覆盖时,旧的 Helper 线程已经在 br.readLine() 内部等待传入来自第一个客户的字符串。
旧的 Helper 线程仅在行到达后读取 brbw 的新值。