TCP客户端/服务器通信为什么只发送第一条消息?

3

我将在Java中设置一个简单的TCP客户端服务器交互。

服务器:

服务器是用Java编写的桌面客户端:

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

class TCPServer
{
    public static int PORT_NUMBER = 6129;

    public static void main(String argv[]) throws Exception
    {
        String clientMessage;
        ServerSocket welcomeSocket = new ServerSocket(PORT_NUMBER);

        while (true)
        {
            Socket connectionSocket = welcomeSocket.accept();

            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));

            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());

            clientMessage = inFromClient.readLine();

            System.out.println("Received: " + clientMessage);

            outToClient.writeBytes("I received this: "+ clientMessage +"\n");
        }
    }
}

客户端:

客户端是一个连接到服务器的Android应用,使用TCP协议。在客户端中,我有一个名为sendMessage(String msg)的方法,它试图向服务器发送一条消息。

public static void sendMessage(String msg) throws IOException
{
    if (mainSocket == null)
    {
        return;
    }
    if (!mainSocket.isConnected())
    {
        connectSocket();
    }
    PrintWriter output = new PrintWriter( mainSocket.getOutputStream());
    output.println(msg);
    output.flush();
    System.out.println(msg);
}

问题是,服务器接收到第一条消息,但任何后续的消息都不会出现。当我关闭客户端时,所有其他消息突然一下子都在服务器上显示出来。

服务器看到的情况如下:

Received: message 1

长时间没有活动...
然后我关闭了客户端

Received: message 2 message 3 message 4 message 5 etc..

我在sendMessage()方法中加入了println,并且该方法正在实时调用。


sendMessage 方法是在什么上下文中运行的?它是从在 UI 线程上运行的 Activity 中运行,还是从在非 UI 线程上运行的某个类中运行? - Jes
sendMessage 是从主 UI 线程中的 Activity 的 onKeyUp 事件调用的。这是否需要在自己的线程中运行? - Razor Storm
我曾经遇到过类似的问题,那是由于线程错误引起的,但是答案似乎是正确的 ;) - Jes
1个回答

6
每次发送消息时,您需要在客户端端口显式地使用close()关闭您的PrintWriter。在从inFromClient读取完成后以及从outToClient写入完成后,同样适用于服务器端口。
此外,还可以参考基本示例,他们很好地解释了基本工作流程:

然而,基础知识与此程序基本相同:

打开一个套接字。

打开输入输出流到该套接字。

按照服务器的协议进行读写。

关闭流。

关闭套接字。


太棒了。我对PrintWriter和socket进行了显式的close()调用,现在它可以工作了。我没有意识到close()不会自动隐式调用。谢谢! - Razor Storm
1
@Razor Storm 这个答案是不正确的。你需要在发送每条消息时刷新PrintWriter,并在对话结束时关闭它。在每条消息之后关闭它会强制执行每条消息的新连接,这是非常浪费的。 - user207421
好的,在我的原始代码中,我在每次 sendMessage 后都有一个 flush() ,并且在 printWriter 和 socket 上都没有关闭,但它仍会出现我所描述的问题。你知道还有其他可能导致这种情况的原因吗? - Razor Storm
看起来你只刷新了客户端,但你还需要在服务器端刷新。EJP 是正确的,每个消息都重新打开一个新连接并不是最优雅的方式,但这种方式仍然有效。你也可以尝试保持连接打开,在特定消息“完成”时每次在两端刷新。 - emboss
看起来我的服务器是按照每个连接一个消息的方式设计的。我在无限循环中加入了一个内部循环,它会执行 while(connectionSocket.isConnected()){//listen for message}。当套接字不再连接时,它将返回到监听模式。 - Razor Storm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接