我要进行最简单的解释。我的Java TCP项目有一个服务器和三个客户端。
服务器具有一个ClientThread。每个客户端都有一个ServerThread和一个UserThread。
工作流程为: 1.客户端(例如,client_0)的UserThread获取用户输入,然后将消息发送到服务器。 2.服务器的ClientThread捕获来自client_0的消息,并将另一条消息发送到另一个客户端(例如client_1)的ServerThread。 3.然后,client_1的ServerThread发送回另一条消息到服务器中运行的ClientThread。
步骤3的消息未到达服务器。
共有3个客户端,例如client_0,client_1和client_2。 最初的想法是,如果client_0请求服务器,则服务器与client_1和client_2通信。这就是if(i==cid) continue;服务器中for循环中的行的原因。但是,如果我注释掉这一行,服务器将与client_0通信(这在语义上是不必要的),并且不会发生消息传递问题。此后,服务器与client_1通信,问题再次出现。
if(i==cid) continue;
服务器可以从客户端(Client_0)的ServerThread接收消息,该消息从其UserThread发送了原始请求(msgToServer.println("get list");),以启动整个过程。但是Server无法从任何其他客户端的ServerThread获取消息,即使它可以将消息发送给其他客户端,并且所有客户端程序都是相同的,并且所有ServerThreads和UserThreads都应该工作相同。怎么可能呢?
msgToServer.println("get list");
服务器:
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!!!");永远不会被调用。
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");已打印。这意味着之前的消息发送行已毫无问题地执行了。
System.out.println("count sent to server");
我知道服务器中的登录系统很愚蠢。但这工作还可以。在所有客户端都已连接并登录到服务器后,上述所有事情都会发生。
我想我已经找到问题了。我为客户端程序的ServerThread和UserThread使用了相同的套接字。因此,当ServerThread尝试响应服务器时,很可能该消息将通过同一套接字发送到服务器中另一个正在侦听消息的线程(认为该消息来自UserThread)。