我想做最简单的解释。我的Java TCP项目有一个服务器和三个客户端。
服务器有一个ClientThread。 每个客户端都有一个ServerThread和一个UserThread。
工作流程为:
1.客户端的UserThread(例如,client_0)获取用户输入,然后向服务器发送消息
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进行通信。这就是服务器中for循环中的行if(i==cid) continue;
的原因。但是,如果我注释掉这一行,服务器会与client_0进行通信(这在语义上是不必要的),并且不会发生消息传递问题。之后,服务器与client_1进行通信,然后再次出现问题。
服务器可以从客户端(client_0)的ServerThread接收消息,该消息从其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");
。这意味着之前的消息发送行已经执行没有问题。
我知道服务器中的登录系统很愚蠢。但这项工作“没问题”。在所有客户端连接并登录到服务器之后,上面解释的所有内容都会发生。
答案 0 :(得分:0)
我想我发现了这个问题。我使用相同的套接字用于客户端程序的ServerThread和UserThread。因此,当ServerThread尝试响应服务器时,很可能该消息将通过同一套接字转发到正在侦听消息的服务器中的另一个不同的线程(认为消息来自UserThread)。