2017-07-18 156 views
1

我正在寻找最简单的解释。我的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");被打印。这意味着之前的消息发送线没有问题地执行。

我知道在服务器上的登录系统是愚蠢的。但对于这项工作来说,这是可以的。上述所有内容均在所有客户端连接并登录到服务器之后进行。

+0

您需要阅读网络教程。您无法在单个线程中同时处理多个客户端。您需要为每个接受的套接字启动一个新的线程。 – EJP

+0

@EJP我没有在一个线程中同时处理多个客户端。而且我还会根据接受的套接字启动一个新的线程。 要求是,当client_0与服务器通信时,服务器必须与client_1进行通信并从client_1获得一些响应,然后将其返回给client_0。你如何建议我可以做到这一点? – ddhrubo

+0

我同意。在单线程中,您一次只能处理多个套接字。你不能。那就是问题所在*。在每个接受的套接字启动一个新的线程之前,你正在与客户端进行各种I/O *这会阻止并阻止你处理更多的客户端。所以不要这样做。 – EJP

回答

0

我想我已经找到了问题。我为客户端程序的ServerThread和UserThread使用相同的套接字。所以,当ServerThread尝试响应服务器时,很可能消息会通过同一个套接字转到正在侦听消息(认为消息来自UserThread)的服务器中的另一个不同线程。

相关问题