【问题标题】:Thread server/client stops after 2nd client joins线程服务器/客户端在第二个客户端加入后停止
【发布时间】:2014-03-29 10:55:17
【问题描述】:

我有一个使用多个线程来接受多个客户端的服务器。我现在有它,当客户端键入某些内容时,它在服务器上显示为 Client: text 这适用于 1 个客户端。然而问题是当第二个客户加入时。

他们可以很好地加入并且可以很好地打字。但是第一个客户端只能再输入 1 件事然后他们停止,即他们的消息不会出现在服务器上。我认为他们可以做 1,因为方法已经开始但不会重复。我尝试了一个 while (true) 循环(如代码中所示)并在最后回忆了该方法,但都不起作用。我是编程新手,所以在这方面没有太多专业知识。请在下面找到代码:)(注意,缩进是正确的,只是没有正确复制)

服务器:

    package dod;

    import java.net.*;
    import java.util.*;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.io.*;

    public class Server implements Runnable
    {
    PrintWriter out;
    BufferedReader in;
    Socket clientSocket;
    ServerSocket serverSocket;
    int portNumber;
    AtomicInteger numClients = new AtomicInteger(0);


    public static void main(String[] args)
    {
        Server s = new Server();

        s.startup();
    }

    public void run()
    {}


    /**
     * Start the server on the user picked port
     */
    public void startup()
    {   
        try 
        {
            System.out.println("Enter a port");
            Scanner dif = new Scanner(System.in);
            portNumber = Integer.parseInt(dif.nextLine());
            dif.close();

            serverSocket = new ServerSocket(portNumber);
            newThread();
        }
        catch (IOException e) {
            System.out.println("Error");
            System.exit(0);
        }
    }


    public void newThread()
    {
        Thread thread =new Thread("C"+numClients.getAndIncrement())
        {
            public void run()
            {
                accept();
            }
        };
        thread.start();
    }

    public void accept()
    {
        try
        {
            clientSocket = serverSocket.accept();
            System.out.println("A new client has just connected.");
        } catch(IOException e)
        {
            System.out.println("error");
            System.exit(0);
        }
        newThread();
        listenCommand();

    }


    public void listenCommand()
    {
        while (true)
        {
            try
            {
                out = new PrintWriter(clientSocket.getOutputStream(), true);                   
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                String userInput;
                while ((userInput = in.readLine()) != null)
                {
                    System.out.println("client: " + userInput);
                }
            } catch (IOException e)
            {
                System.out.println("Error");
                System.exit(0);
            }
        }
    }
}

客户:

    package dod;

    import java.io.*;
    import java.net.*;


    public class Client
    {
    public static void main(String[] args) throws IOException {
        String hostName = args[0];
        int portNumber = Integer.parseInt(args[1]);

        try {
            Socket serverSocket = new Socket(hostName, portNumber);
            PrintWriter out = new PrintWriter(serverSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

            String userInput;
            while ((userInput = stdIn.readLine()) != null)
            {
                out.println(userInput);
            }
        } catch(UnknownHostException e) {
            System.out.println("error in host");
        } catch(IOException e) {
            System.out.println("error in IO");
        }


    }
}

谢谢! :)

【问题讨论】:

    标签: java multithreading networking client


    【解决方案1】:

    *强调文本*在 Server 类中,您应该有一个 Thread 监听新客户端的到来并为它们分配自己的套接字。您将套接字和流作为成员变量,因此每次有新客户端出现时,您都会替换套接字。您还为接受连接打开一个新线程,而不是为客户端本身打开一个新线程。

    检查以下内容(看到客户端套接字是另一个线程,我为它创建了一个 Runnable):

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class Server
    {
        ServerSocket serverSocket;
        int portNumber;
        AtomicInteger numClients = new AtomicInteger(0);
    
    
        public static void main(String[] args)
        {
            Server s = new Server();
    
            s.startup();
        }
    
    
        /**
         * Start the server on the user picked port
         */
        public void startup()
        {   
            try 
            {
                System.out.println("Enter a port");
                Scanner dif = new Scanner(System.in);
                portNumber = Integer.parseInt(dif.nextLine());
                dif.close();
    
                serverSocket = new ServerSocket(portNumber);
                newThread();
            }
            catch (IOException e) {
                System.out.println("Error");
                System.exit(0);
            }
        }
    
    
        public void newThread()
        {
            Thread thread =new Thread("C"+numClients.getAndIncrement())
            {
                public void run()
                {   
                    while(true) {
                        try {
                            accept();
                        } catch (Exception e) {
                            // lof the exception
                        }
                    }
                }
            };
            thread.start();
        }
    
        public void accept()
        {
            try
            {
                Socket clientSocket = serverSocket.accept();
                new Thread(new ClientSocket(clientSocket)).start();
                System.out.println("A new client has just connected.");
            } catch(IOException e)
            {
                System.out.println("User disconnected");
                System.exit(0);
            }
        }
    
    
        class ClientSocket implements Runnable {
            Socket clientSocket;
    
            public ClientSocket(Socket clientSocket) {
                this.clientSocket = clientSocket;
            }
    
            public void run() {
                {
                    try
                    {
                        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);                   
                        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    
                        String userInput;
                        while ((userInput = in.readLine()) != null)
                        {
                            System.out.println("client: " + userInput);
                        }
                    } catch (IOException e)
                    {
                        System.out.println("Error. Probably client disconnected");
                        // System.exit(0); do you want to exist when a client disconnects?
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 快到了。不完全的。流仍然是类变量。服务器类中应该有没有线程级变量。
    • 好,+1。我唯一要指出的是,现在为每个连接生成线程是非常危险的——它使 DOS 攻击变得轻而易举。正确的方法是使用thread pool。更高级的方法是使用NIO
    • P.S.为什么你的Serverimplements Runnable?这似乎毫无用处。
    • @Raul Guiu 谢谢,我会看看并试一试 :) 非常感谢
    • @pokeairguy 查看代码 - Server 未在 Thread 中使用。