Java TCP Echo Server – 广播

我有一个简单的echo服务器,我希望当一个连接的用户向服务器输入任何内容时,所有其他客户端和该客户端将得到一条消息+“| MOD”。

它现在不会发送给所有客户,但它应该,我只是不知道我的代码有什么问题,所以现在它只会将消息+“| MOD”发送给发送消息的客户端,但不会发送给所有其他客户端这应该。

我只是不明白,我有一个遍历所有客户端的循环,但它仍然不会发送给所有客户端。

服务器:

package com.murplyx.server; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class Server { public static ServerSocket server; public static ArrayList clients = new ArrayList(); public static void broadcast(String message) { try { for (Socket socket : clients) { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); out.println(message); } } catch(Exception e) { e.printStackTrace(); } } public static void main(String args[]) { try { server = new ServerSocket(9000); while (true) { clients.add(server.accept()); for (Socket socket : clients) { BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = in.readLine(); if (line != null) { broadcast(line + " | MOD"); } } } } catch(Exception e) { e.printStackTrace(); } } } 

客户:

 package com.murplyx.client; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class Client { public static void main(String args[]) { try { while (true) { Socket socket = new Socket("localhost", 9000); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); out.println(input.readLine()); System.out.println(in.readLine()); socket.close(); } } catch (Exception e) { e.printStackTrace(); } } } 

请帮忙。

非常感谢。

您遇到的一个问题是每个客户端将重复执行read stdin, write socket, read socket, write stdout, ... ad infinitum。

当你广播所有其他客户端仍然通常坐在read stdin阶段,所以他们不知道有什么东西等待在socket上读取。 他们还在等待用户输入内容。

最简单的选择之一是在每个客户端中启动两个线程 – 一个只处理read stdin, write socket, ... ,另一个处理read socket, write stdout

[另一个(可能更复杂)选项我们使用Java NIO同时轮询套接字和stdin以获取可用输入]。

第二个问题是您在服务器中的accept调用中阻塞,然后依次从每个套接字读取。 您可以在一个线程中accept ,并且每个客户端只从客户读取另一个线程,并重新广播到其他线程。 NIO也可以是一个很好的选择 – 您可以轮询读取任何客户端。

我不确定ArrayLists如何使用套接字,所以我肯定会回到使用普通数组(请参阅编辑后的代码Java EchoTCPServer – 发送给所有客户端 )

我认为我认为有些事情可以解决:

在客户端:

– 在While循环中停止关闭套接字。 在while循环外面关闭它(当客户端完成服务器时)。 另外,在Loop外面声明套接字。

注意 :当客户端使用套接字连接到服务器时,会自动为其提供设备端口,因此两个不同的设备永远不会将相同的IP连接到服务器。 TCP连接由2个端口,服务器套接字和客户端套接字组成,套接字由[deviceip:port,serverip:port](iirc)表示。

– 此外,在客户端上,每次进入while循环时都不需要声明新的阅读器。 把它全部放在外面。 while循环中唯一的内容应该是readline + print语句。

-readLine是一种阻止方法。 (以防万一你不知道这意味着什么,这意味着readLine将使你的程序被卡在那里直到它实际读取一行。为了绕过它,你可以使用if语句结合.ready()函数ready函数检查是否有“读入”的内容,因此如果没有输入则不会卡在“readLine”上。

在服务器上:

– 就像我之前说过的那样,我会改回使用普通arrays。

– 你的服务器仍然会卡在.accept()上。 因此,除了每次连接之后,您将永远无法读取客户端的输入。 您可以使用线程来收听,它仍然可以工作。

例如:(此代码附带我附加的链接中的代码(也是您的问题),将其放在服务器的while循环之前)

 // create a tcp listener thread to deal with listening to clients Thread listenerThread = new Thread() { public void run() { String clientSentence; while (true) { //loop through each connected socket for (int i = 0; i <= intLastSocket; i++) { Socket z = clientSocket[i]; //make sure the socket is not null or closed (can't do anything //with closed or null sockets if ((z != null) && (!z.isClosed())) { try { // Deal with TCP input here BufferedReader input = new BufferedReader(new InputStreamReader(z.getInputStream())); // read in a line but only if there is one if (input.ready()) { clientSentence = input.readLine(); } } catch (IOException x) { printTCP("IOException caught when reading in: " + x.toString()); } if (clientSentence != null) { System.out.println("Received from client: " + clientSentence); //send this message to the client outputStream[i].println(clientSentence + " | MOD"); } // clear the input clientSentence = null; } } } } }; listenerThread.start();