Java TCP服务器无法接收来自多个客户端的消息
我正在寻找最简单的解释。我的Java TCP项目有一个服务器和三个客户端。Java TCP服务器无法接收来自多个客户端的消息
服务器有一个ClientThread。 每个客户端都有一个ServerThread和一个UserThread。
工作流程如下:
1.客户端的UserThread(例如client_0)获取用户输入,然后向服务器发送消息。
2.服务器的ClientThread捕获来自client_0的消息并向另一个客户端的ServerThread(比如client_1)发送另一条消息。
3. client_1的ServerThread接着发送另一个消息给服务器中运行的ClientThread;
步骤3的消息未到达服务器。
总共有3个客户端,分别是client_0,client_1和client_2。
最初的想法是,如果client_0请求服务器,则服务器与client_1和client_2进行通信。这就是为什么服务器中for循环中的行if(i==cid) continue;
。但是,如果我注释掉这一行,服务器将与client_0进行通信(这在语义上是不必要的),并且不会发生消息传递问题。之后,服务器与client_1通信,问题再次出现。
服务器可以从客户端的ServerThread(client_0)接收消息,该消息从它的UserThread发送原始请求(msgToServer.println("get list");
)以启动整个过程。但是服务器无法从任何其他客户端的ServerThread中获取消息,即使它可以将消息发送给其他客户端,并且所有客户端程序都是相同的,并且所有的ServerThreads和UserThreads都应该以相同的方式工作。这怎么可能?
服务器:
package serverftp;
import java.io.*;
import java.net.*;
public class ServerFTP {
static String[] id = {"cp 1","cp 2","cp 3"};
static String[] pass = {"123","456","789"};
static BufferedReader[] msgFromClient = new BufferedReader[3];
static PrintWriter[] msgToClient = new PrintWriter[3];
static InputStream[] fileFromClient = new InputStream[3];
static OutputStream[] fileToClient = new OutputStream[3];
public static void main(String[] args) throws Exception {
ServerSocket welcome = new ServerSocket(6789);
// connecting the three clients
for(int i=0; i<3; i++) {
System.out.println("Waiting for Client "+i);
Socket clientSocket;
clientSocket = welcome.accept();
while(true) {
System.out.println("Connecting Client "+i);
BufferedReader fromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter toClient = new PrintWriter(clientSocket.getOutputStream(),true);
// get id pass from client
String clientId = fromClient.readLine();
System.out.println(clientId);
String clientPass = fromClient.readLine();
System.out.println(clientPass);
// check id pass and feedback
if(clientId.equals(id[i]) && clientPass.equals(pass[i])) {
toClient.println("ok");
msgFromClient[i] = fromClient;
msgToClient[i] = toClient;
fileFromClient[i] = clientSocket.getInputStream();
fileToClient[i] = clientSocket.getOutputStream();
break;
} else {
toClient.println("error");
}
}
ClientThread ct = new ClientThread(i);
ct.start();
System.out.println("Client "+i+" connected!");
}
welcome.close();
}
}
class ClientThread extends Thread {
int cid;
String msg;
public ClientThread(int client_id) {
cid = client_id;
try {
// telling client it's serial
ServerFTP.msgToClient[cid].println(Integer.toString(cid));
} catch(Exception ex) {
ex.printStackTrace();
}
}
@Override
public void run() {
while(true) {
try {
// get request from receiver
msg = ServerFTP.msgFromClient[cid].readLine();
if(msg.equals("get list")) {
System.out.println(cid+" "+msg);
msg = ServerFTP.msgFromClient[cid].readLine();
System.out.println(cid+" "+msg);
for(int i=0; i<3; i++) {
if(i==cid) continue;
// send sender request for file list
ServerFTP.msgToClient[i].println("give list");
System.out.println("request sent to client "+i);
// get file count from sender
msg = ServerFTP.msgFromClient[i].readLine();
System.out.println("file count caught!!!"); // THIS LINE NEVER EXECUTES
System.out.println("File count "+msg);
}
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
}
线System.out.println("file count caught!!!");
永远不会被调用。
客户:
package clientftp_1;
import java.io.*;
import java.net.*;
public class ClientFTP_1 {
static String[] allPaths = { "...path...\\client_1_folder",
"...path...\\client_2_folder",
"...path...\\client_3_folder"};
public static void main(String[] args) throws Exception {
InetAddress inetAddress = InetAddress.getLocalHost();
Socket server = new Socket(inetAddress,6789);
int myId;
// login phase
BufferedReader fromUser = new BufferedReader(new InputStreamReader(System.in));
BufferedReader fromServer = new BufferedReader(new InputStreamReader(server.getInputStream()));
PrintWriter toServer = new PrintWriter(server.getOutputStream(),true);
InputStream getFile = server.getInputStream();
OutputStream sendFile = server.getOutputStream();
while(true) {
System.out.println("id: ");
String msg = fromUser.readLine();
toServer.println(msg);
System.out.println("password: ");
msg = fromUser.readLine();
toServer.println(msg);
msg = fromServer.readLine();
if(msg.equals("ok")) {
System.out.println("Connection Successful!");
myId = Integer.parseInt(fromServer.readLine());
System.out.println("Client serial is: "+myId);
System.out.println("Folder path is: "+allPaths[myId]);
break;
} else {
System.out.println("Error! Try again please.");
}
}
ServerThread st = new ServerThread(allPaths[myId],fromUser,fromServer,toServer,getFile,sendFile);
st.start();
UserThread ut = new UserThread(allPaths[myId],fromUser,fromServer,toServer,getFile,sendFile);
ut.start();
}
}
class ServerThread extends Thread {
String folderPath;
String msg;
BufferedReader msgFromServer,msgFromUser;
PrintWriter msgToServer;
InputStream fileFromServer;
OutputStream fileToServer;
public ServerThread(String path,BufferedReader fromUser,BufferedReader fromServer,PrintWriter toServer,InputStream getFile,OutputStream sendFile) throws Exception {
folderPath = path;
msgFromUser = fromUser;
msgFromServer = fromServer;
msgToServer = toServer;
fileFromServer = getFile;
fileToServer = sendFile;
}
@Override
public void run() {
System.out.println("Server Thread Started");
while(true) {
try {
// receive request
msg = msgFromServer.readLine();
System.out.println("request received from server");
if(msg.equals("give list")) {
// get filenames
File folder = new File(folderPath);
File[] fileList = folder.listFiles();
int cnt = fileList.length;
System.out.println("count calculated");
// sned file count to server
msgToServer.println(Integer.toString(cnt));
System.out.println("count sent to server"); // THIS LINE PRINTS
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
}
class UserThread extends Thread {
String folderPath;
String msg;
BufferedReader msgFromServer,msgFromUser;
PrintWriter msgToServer;
InputStream fileFromServer;
OutputStream fileToServer;
public UserThread(String path,BufferedReader fromUser,BufferedReader fromServer,PrintWriter toServer,InputStream getFile,OutputStream sendFile) throws Exception {
folderPath = path;
msgFromUser = fromUser;
msgFromServer = fromServer;
msgToServer = toServer;
fileFromServer = getFile;
fileToServer = sendFile;
}
@Override
public void run() {
System.out.println("USer Thread Started");
while(true) {
try {
// input from user
msg = msgFromUser.readLine();
if(msg.equals("get list")) {
// send request to server
msgToServer.println("get list");
msgToServer.println("fahim list");
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
}
线System.out.println("count sent to server");
被打印。这意味着之前的消息发送线没有问题地执行。
我知道在服务器上的登录系统是愚蠢的。但对于这项工作来说,这是可以的。上述所有内容均在所有客户端连接并登录到服务器之后进行。
我想我已经找到了问题。我为客户端程序的ServerThread和UserThread使用相同的套接字。所以,当ServerThread尝试响应服务器时,很可能消息会通过同一个套接字转到正在侦听消息(认为消息来自UserThread)的服务器中的另一个不同线程。
您需要阅读网络教程。您无法在单个线程中同时处理多个客户端。您需要为每个接受的套接字启动一个新的线程。 – EJP
@EJP我没有在一个线程中同时处理多个客户端。而且我还会根据接受的套接字启动一个新的线程。 要求是,当client_0与服务器通信时,服务器必须与client_1进行通信并从client_1获得一些响应,然后将其返回给client_0。你如何建议我可以做到这一点? – ddhrubo
我同意。在单线程中,您一次只能处理多个套接字。你不能。那就是问题所在*。在每个接受的套接字启动一个新的线程之前,你正在与客户端进行各种I/O *这会阻止并阻止你处理更多的客户端。所以不要这样做。 – EJP