【问题标题】:Creating a Multi-threaded Java Server Chat App.创建多线程 Java 服务器聊天应用程序。
【发布时间】:2025-11-24 07:05:01
【问题描述】:

我正在尝试用 Java 实现一个多线程服务器聊天应用程序。
该程序创建了一个线程并等待客户端连接。一旦客户端连接,它会创建另一个线程并等待另一个客户端连接。

这是我的ChatServer.java

package com.chat.server;



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



/**
 * <p>The chat server program</p>
 * This class is a Thread that recieves connection
 * from different clients and handles them is separate
 * Thread.
 *
 * @author Aditya R.Singh
 * @version 1.0.0
 * @since 1.0.0
 */
class ChatServer extends Thread {

    private int port;                    // The port number to listen at.
    private String ip;                   // To store the IP address.
    private Socket socket;               // Socket connection with different clients.
    private InetAddress inet;            // Handling Client Address.
    private ServerSocket serverSocket;   // The server socket used by clients to connect.



    /**
     * This is solely intended for instantiation purpose.
     * 
     * @param PORT - The port number to listen for client requests
     */
    ChatServer(final int PORT) {


        /* Initiallizing all instance variables to null. */
        ip = null;
        inet = null;
        socket = null;
        serverSocket = null;

        /* Initiallizing the port number. */
        port = PORT;
    }



    /**
     * This method creates a connection between server and client.
     * 
     * @throws java.io.IOException
     */
    private void createConnection() throws IOException {

        serverSocket = new ServerSocket(port);  // Listen to the required port. 
        socket = serverSocket.accept();         // Accept the client connection.
    }



    /**
     * This method sets the IP address.
     */
    private void setIP() {

        inet = socket.getInetAddress();
        ip = new String(inet.getHostAddress());
    }



    /**
     * This method returns the IP address.
     *
     * @return IP address.
     */
    public String getIP() {

        return ip;
    }



    /**
     * This method checks if the socket has been connected
     * with any client.
     *
     * @return True if the client has been connected, else false
     */
    public boolean isConnected() {

        if(socket == null)
            return false;
        return true;
    }



    /**
     * This method returns the InputStream
     * from the Socket.
     * 
     * @return InputStream if Socket has been connected to the client, else null
     * @see java.io.InputStream
     */
    public InputStream getInputStream() throws IOException {

        if(socket == null)
            return null;
        return socket.getInputStream();
    }



    @Override
    public void run() {

        try {

            createConnection();
            setIP();
        } catch(IOException exception) {

            exception.printStackTrace();
        }
    }
}  

这是我的Server.java

package com.chat.server;



/** 
 * <p>The Server app</p> 
 * This is the controller for accepting connections.
 *
 * @author Aditya R.Singh 
 * @version 1.0.0
 * @since 1.0.0
 */
public class Server {


    /**
     * The port at which clients will connect.
     */
    public static final int PORT = 6005;          



    /**
     * For instantiation purpose.
     */
    public Server() {


    }



    public static void main(String[] args) {


        /* Keep accepting connections. */
        while(true) {

            ChatServer chat = new ChatServer(PORT); // Connecting port.
            chat.start();

            while(!chat.isConnected())
                /* This is a false loop. Intended to keep running unless another client is not requesting to connect. */;

            System.out.println("We connected to: "+chat.getIP());   
        }
    }
}  

代码编译良好。
将代码运行为:

java com.chat.server.Server  

似乎程序正在监听客户端连接。但是在它连接到客户端之后,它应该打印客户端的 IP 地址,然后为另一个客户端创建另一个线程。但它不会打印客户端的 IP。

这是我的Client.java

package com.chat.client;



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



public class Client {

    public static void main(String[] args) {

        Socket socket = null;


        try {

            socket = new Socket("127.0.0.1", 6005);
            System.out.println("Socket connected.");
        } catch(IOException ex) {

            ex.printStackTrace();
        }
    }
}  

客户端连接到服务器,必须打印Socket connected。客户这样做。客户端工作正常:

java com.chat.client.Client  
Socket connected.  

但服务器应用程序不打印客户端的 IP 地址。为什么会这样?

【问题讨论】:

  • 这个code 可能会让你知道如何做一个聊天服务器。

标签: java multithreading sockets


【解决方案1】:

这不是完整的代码

package demo;

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



public class MultithreadedServer {

    public static final int PORT = 10000;

    public static void main(String[] args) {
        try(ServerSocket server = new ServerSocket(PORT)) {
            while(true){
                Socket connection = server.accept();
                Thread client = new ClientThread(connection);
                client.start();
            }
        } catch (IOException ex) {
            System.out.println("Error start server");
        }
    }

}

class ClientThread extends Thread {
    private Socket connection;

    public ClientThread(Socket connection) {
        this.connection = connection;
    }

    @Override
    public void run(){
        //Do communication with client
    }

}

【讨论】:

    【解决方案2】:

    这是一个竞争条件。 socket = serverSocket.accept(); 行导致while(!chat.isConnected()) 循环在调用方法“setIP()”之前终止。验证这是问题原因的一种快速方法是更改​​此方法:

    public boolean isConnected() {
        if(socket == null)
            return false;
        return true;
    }
    

    public boolean isConnected() {
        if(socket == null || ip == null)
            return false;
        return true;
    }
    

    为了解决问题,您应该确保设置 IP 的代码和检查是否已连接的代码使用 synchronized 关键字。另外,请注意while(!chat.isConnected()) 循环运行时没有暂停,这意味着它会占用尽可能多的 CPU 资源......这绝对不好。

    查看@Michael Petch 发布的链接以正确实施聊天服务器。

    【讨论】: