Java套接字问题:消息只能传递一次

Java套接字问题:消息只能传递一次,java,sockets,tcp,Java,Sockets,Tcp,最近,我正在尝试一个练习,该练习要求设计一个具有两个基于tcp套接字的客户端的服务器。连接后,SenderClient应将用户键入的消息发送到服务器,然后服务器应将该消息转发给ReceiverClient。就像: 发送客户端->服务器->接收客户端 只有当用户类型在sender中退出时,所有程序才会终止,否则它们总是在侦听消息 现在我遇到的问题是:当我在EclipseLuna中运行这三个程序时,我发现消息只能从SenderClient->Server->ReceiverClient成功传递一次。

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

发送客户端->服务器->接收客户端

只有当用户类型在sender中退出时,所有程序才会终止,否则它们总是在侦听消息

现在我遇到的问题是:当我在EclipseLuna中运行这三个程序时,我发现消息只能从SenderClient->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

ServerSocket的accept方法是一个阻塞操作:它等待传入的连接,直到该代码运行的线程等待。第一次正确执行循环是因为两个客户端连接到服务器。第二次执行循环时,您将等待另一个传入的客户端。解决方案是通过实现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;
        }
    }
}
}

每当服务器获得两个传入连接时,它就会启动一个新线程来处理该连接,然后继续接受新的传入连接:

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();
}

你怎么知道接收器总是先连接?为什么在收到或发送每封邮件后都要关闭套接字,而不是让它一直打开直到对话真正结束。分配需要它,首先连接接收器。很抱歉,我没有把它描述清楚。2.起初,当我只测试单个阶段的服务器->客户端或客户端->服务器时,我试图在每条消息之后不关闭套接字,但结果总是不好。在我将socket.close移出if循环之后,当用户类型退出时,它终止,程序工作。这就是原因,尽管我真的不知道为什么会奏效。我只是在测试和修复。是的,我现在看到了我的问题。谢谢你的评论。提示:在客户端,每次连接时都打印本地端口。在服务器中,每次接受连接时都打印每个套接字的端口。您将看到发件人在第一条消息之后首先连接。不要断开连接,非常感谢。我正在努力理解这一点。你有可能重写类服务器吗?我正试图按照你的方式修改代码,但要成功编译似乎相当困难……哦,非常感谢你。但是,当我运行您的程序时,在ClientConnection.runServer.java:64处的thread-0 java.lang.NullPointerException中出现了一个异常,该异常位于java.lang.thread.runUnknown Source,感谢您的帮助,我将尝试更正它。可能与流关闭有关,正如我从文档中读到的,如果流关闭,readLine可以返回null: