Java Socket问题:消息只能传递一次



最近我正在尝试一个练习,需要基于tcp套接字设计一个具有两个客户端的服务器。在连接之后,sendclient应该发送用户输入的消息给Server,然后Server应该将该消息转发给ReceiverClient。就像:

sendclient -> Server -> ReceiverClient

只有当用户在sender中输入"quit"时,所有的程序将被终止,否则它们将一直监听消息。

现在我遇到了这样的问题:当我在Eclipse Luna中运行这三个程序时,我发现消息只能从sendclient -> Server -> ReceiverClient成功传递一次。在此之后,消息将在服务器上被阻塞。你们能在电脑上运行这三个程序看看这个奇怪的现象吗?谢谢你,我真的需要帮助。

import java.io.*;
import java.net.*;
public class Server {
public static void main (String args[]) {
    InputStream is = null;
    InputStreamReader isr = null;
    BufferedReader br = null;
    OutputStream os = null;
    PrintWriter pw = null;
    String info = null;
    try {
        // listening to port
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("Server is listening to port 8888...");
        while (true) {
            // respond to clients
            Socket receiverSocket = serverSocket.accept();
            System.out.println("receiver client connected!");
            Socket senderSocket = serverSocket.accept();
            System.out.println("sender client connected!");
            // get input stream, read messages from sender
            is = senderSocket.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            info = br.readLine();
            // close all resources when user types "quit"
            if (info.equalsIgnoreCase("quit")) {
                // close resources when user types "quit"
                is.close();
                isr.close();
                br.close();
                os.close();
                pw.close();
                serverSocket.close();
                System.out.println("Server terminated!");
                break;
            }
            // print out the message
            if (info != null) {
                System.out.println("Sender -> Server: " + info);
            }               
            // get output stream, forward messages to receiver          
            os = receiverSocket.getOutputStream();
            pw = new PrintWriter(os);
            pw.println(info);
            pw.flush();
        } // end while
    } catch (IOException e) {
        e.printStackTrace();
    } // end try...catch
} // end main method
} // end class Server

import java.io.*;
import java.net.*;
public class ReceiverClient {
    public static void main (String args[]) {
        InputStream is = null;
        BufferedReader br = null;
        String info = null;
        try {
            while (true) {
                // create receiver socket with host and port number
                Socket receiverSocket = new Socket("localhost", 8888);
                // get input stream, read the information
                is = receiverSocket.getInputStream();
                br = new BufferedReader(new InputStreamReader(is));
                info = br.readLine();
                // close all resources when user types "quit"
                if (info.equalsIgnoreCase("quit")) {
                    is.close();
                    br.close();
                    System.out.println("Receiver client terminated!");
                    break;
                }
                // print out the message
                if (info != null) {
                    System.out.println("Sender -> Server -> Receiver: " + info);
                }
                receiverSocket.close();
            } // end while
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } // end try...catch
    } // end main method
} // end class ReceiverClient
import java.io.*;
import java.net.*;
public class SenderClient {
    public static void main (String args[]) {
        OutputStream os = null;
        PrintWriter pw = null;
        BufferedReader br = null;
        String userInput = null;
        try {
            while (true) {
                // create sender socket with host and port number
                Socket senderSocket = new Socket("localhost", 8888);
                // get message from user input
                System.out.println("Please input a message:");
                br = new BufferedReader(new InputStreamReader(System.in));
                userInput = br.readLine();
                // get output stream, send message to server
                os = senderSocket.getOutputStream();
                pw = new PrintWriter(os);
                pw.println(userInput);
                pw.flush();
                senderSocket.close();
                // close all resources when user types "quit"
                if (userInput.equalsIgnoreCase("quit")) {
                    os.close();
                    pw.close();
                    System.out.println("Sender client terminated!");
                    break;
                }
            } // end while
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } // end try...catch    
    } // end main method
} // end class SenderClient

Socket receiverSocket = serverSocket.accept();

ServerSocketaccept()方法是一个阻塞操作:它等待一个传入的连接,直到这个代码运行的线程等待。第一次正确执行循环,因为两个客户机连接到服务器。第二次执行循环时,您将等待另一个传入的客户机。对此的解决方案是通过实现java.lang.Runnable接口在单独的线程中处理消息,该接口是在新启动的线程上运行的代码:

class ClientConnection implements Runnable{
private Socket sender;
private Socket receiver;
public ClientConnection(Socket sender, Socket receiver){
    this.sender = sender;
    this.receiver = receiver;
}
@Override
public void run(){
    is = sender.getInputStream();
    isr = new InputStreamReader(is);
    br = new BufferedReader(isr);
    OutputStream os = receiver.getOutputStream();
    PrintWriter pw = new PrintWriter(os);
    boolean clientQuit = false;
    while(!clientQuit){
        info = br.readLine();   
        if (info.equalsIgnoreCase("quit")) {
            // close resources when user types "quit"
            is.close();
            isr.close();
            br.close();
            os.close();
            pw.close();
            serverSocket.close();
            System.out.println("Server terminated!");
            clientQuit = true;
        } else{
            pw.println(info);
            pw.flush;
        }
    }
}

}

当服务器收到两个传入连接时,它会触发一个新的Thread来处理这个连接,然后继续接受新的传入连接:

while (true) {
    // respond to clients
    Socket receiverSocket = serverSocket.accept();
    System.out.println("receiver client connected!");
    Socket senderSocket = serverSocket.accept();
    System.out.println("sender client connected!");
    ClientConnection connection = new ClientConnection(senderSocket, receiverSocket);
    Thread connectionThread = new Thread(connection);
    connectionThread.start();
}

最新更新