【问题标题】:Java Sockets - Running the same client multiple times in parallel.Java Sockets - 并行运行同一个客户端多次。
【发布时间】:2015-10-22 05:39:41
【问题描述】:

(声明部分代码与在线教程相似)


我想我已经做到了,以便我的服务器可以使用线程一次处理多个请求,但我不完全确定。最重要的是,我不知道我将如何一次发送多个请求。

我的目标是并行运行我的客户端代码多次,看看如果多个客户端同时连接到服务器会发生什么。

客户端代码(在单独的项目包中):

        Client clientSocket = new Client(9990,"localhost");
        Socket socket = new Socket(clientSocket.host,clientSocket.portNumber);
        clientSocket.performTask(socket);

("performTask(socket)" 向服务器发送数据以执行任务)

服务器代码(将项目包与客户端代码分开):

    Server server = new Server(9990);
    int clientNumber = 0;
    ServerSocket socket = new ServerSocket(server.portNumber);
    try { 
        while (true) {
            new ServerHandler(socket.accept(),clientNumber).go();
            clientNumber++;
        }
    }
    finally {
        socket.close();
        }
}

ServerHandler 类(与服务器代码相同的项目包):

public class ServerHandler extends Thread {
    private static Socket socket;
    private static int clientNumber;

    public ServerHandler(Socket socket, int clientNumber) {
        ServerHandler.socket = socket;
        ServerHandler.clientNumber = clientNumber;
    }

    public void go() {
        while(true) {
        try {
            //do calculation, do server tasks, etc.
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        }
    }

所以当客户端连接到服务器时,服务器会实现 ServerHandler 类来进行必要的计算:这样做的想法是多个客户端可以同时连接。

所以我的问题分为两部分:

(1) 我是否设置了我的程序以允许多线程,或者我在此过程中的某个地方犯了错误? (例如,有人告诉我我需要在某处使用“Runnable”来使用多线程,但我注意到我没有)

(2) 在修复我的代码以允许多线程之后,我将如何实际使用它来让我并行运行我的客户端代码?

【问题讨论】:

    标签: java multithreading sockets parallel-processing client-server


    【解决方案1】:

    好的,首先,您的 ServerHandler 扩展了 Thread 类。因此,要使其作为单独的线程运行,请始终通过调用start() 方法来调用。您正在调用自定义go 方法,这将使ServerHandler 在与无限while 循环相同的线程中执行。所以它应该是这样的ServerHandler(socket.accept(),clientNumber).start()。此外,实现 Runnable 总是更好,因为 java 不支持通过“扩展”概念进行多重继承。因此,将来如果您的 ServerHandler 需要实际扩展自定义类,它将无法扩展,因为它已经扩展了 Thread 类。最好实现接口,因为您可以实现的数量没有限制。

    因此实现 Runnable 接口是一个不错的设计选择。您可以通过将客户端设为线程模型来并行运行客户端代码。这是多个客户端套接字并行连接到服务器的一个示例

    服务器代码

    public class WebServer {
        static int hitCount = 0;
    
        public static void main(String[] args) throws Exception {
            ServerSocket serverSocket = new ServerSocket(7777, 10000);
            while (true) {
                Socket defaultSocket = serverSocket.accept();
                new Thread(new ServerSlave(defaultSocket)).start();
                System.out.println("Size is :" + hitCount);
            }
    
        }
    }
    
    class ServerSlave implements Runnable {
        Socket clientSocket;
    
        public ServerSlave(Socket socket) {
            clientSocket = socket;
            WebServer.hitCount++;
        }
    
        public void run() {
    
            try {
    
                DataInputStream inputStream = new DataInputStream(clientSocket.getInputStream());
                DataOutputStream outputStream = new DataOutputStream(clientSocket.getOutputStream());
                System.out.println(inputStream.readUTF());
                outputStream.writeUTF("Thank you for contacting the web server");
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    客户代码:

    public class Client {
        static int excepCount=0;
        public static void main(String[] args) throws Exception {
            for (int i = 0; i < 100; i++) {
                new Thread(new Worker("" + i)).start();
            }
            Thread.sleep(10000);
            System.out.println( Client.excepCount);
        }
    }
    
    
    class Worker implements Runnable {
        String clientName;
    
        public Worker(String name) {
            clientName = name;
        }
    
        public void run() {
            System.out.println("Process started for : " + clientName);
            Socket socket = null;
            try {
                socket = new Socket("127.0.0.1", 7777);
                DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
                outputStream.writeUTF("Hello socket. Client number " + clientName + "here");
                InputStream inFromServer = socket.getInputStream();
                DataInputStream in =
                        new DataInputStream(inFromServer);
                System.out.println("Server says " + in.readUTF());
                System.out.println("Closing socket");
    
            } catch (IOException e) {
                Client.excepCount++;
                e.printStackTrace();
            }finally{
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    【讨论】:

    • 感谢您的解释,所以我从客户端生成多个同时请求的方法是在客户端项目中拥有第二类,并且类似于我在服务器项目中的第二类?
    • 您可以这样做,也可以让客户端类本身实现 Runnable,然后在 main 方法中创建一个循环并生成一个新的 Thread 对象并将其传递给您的客户端实例并调用 start on它。 :)
    • 是的!我这样做了,并使用了从 i=0 到 1 的循环,它起作用了。但是当我做 2 或任何更高的值时,它就不起作用了。它似乎刚刚开始永远运行。我不太确定有什么问题:(
    • 我正在将值读取到服务器端,如果我有超过 1 个客户端,它只会在中途停止(我使用 for 循环读取,而对于 2 个客户端,它只执行一半的迭代和然后停止并进入无限循环)。
    • 从第一个线程读取输入后出现 EOF 异常
    【解决方案2】:

    你应该使用多线程。 您必须将方法重命名为“run”/并使用“start”调用该方法。请将服务器端代码更改为

    try { 
            while (true) {
                new ServerHandler(socket.accept(),clientNumber).start();
                clientNumber++;
            }
        }
        finally {
            socket.close();
            }
    

    和客户端

    public class ServerHandler extends Thread {
        private static Socket socket;
        private static int clientNumber;
    
        public ServerHandler(Socket socket, int clientNumber) {
            ServerHandler.socket = socket;
            ServerHandler.clientNumber = clientNumber;
        }
    
        public void run() {
            while(true) {
            try {
                //do calculation, do server tasks, etc.
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            }
    

    【讨论】:

    • 我修复了 run() 与 start(),但我的客户端与我的 ServerHandler 类位于不同的项目包中。更改 run() 和 start() 后,我现在如何从客户端生成并发请求?
    • 如果您无法从单独的计算机上运行您的客户端项目,您可以做的是从您的计算机上多次运行您的客户端项目。大多数 IDE 都支持 .您使用的是哪个 IDE?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 1970-01-01
    相关资源
    最近更新 更多