java - 为什么 Java writeBytes 在第一个 TCP 数据包中只发送一个字节并保留在另一个 TCP 数据包中

标签 java sockets tcp network-programming client-server

我正在使用 this 开发一个简单的客户端服务器程序关联。我的服务器是 Mac 机器,客户端是 Windows 机器 (Win 10)。

客户端-服务器通信工作正常。当我检查使用 Wireshark 发送的字节时,在第一个 TCP 数据包中只发送了一个字符。还有另一个 TCP 数据包,其余数据将在其中发送。

即如果我发送“qwerty”,客户端发送“q”,服务器响应,然后客户端发送“werty”。类似地,服务器发送“Q”,客户端响应,然后服务器发送“WERTY”。

这是我的客户端服务器代码。我在执行 writeBytes() 后刷新数据。

如何强制在单个 TCP 数据包中发送数据?

客户端代码:

import java.io.*;
import java.net.*;

class Client
{
    public static void main(String argv[]) throws Exception
    {
        String sentence;
        String modifiedSentence;
        BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in));
        Socket clientSocket = new Socket("192.1.162.65", 6789);
        DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        System.out.println("Enter some text: " + inFromServer);
        sentence = inFromUser.readLine();
        outToServer.writeBytes(sentence + '\n');
        outToServer.flush();
        modifiedSentence = inFromServer.readLine();
        System.out.println("FROM SERVER: " + modifiedSentence);
        clientSocket.close();
    }
}

服务器代码:

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

public class Server {

    public static void createListener(ServerSocket serverSocket) throws Exception {

        String clientSentence;
        String capitalizedSentence;
        @SuppressWarnings("resource")
        ServerSocket welcomeSocket = new ServerSocket(6789);

        while (true) {
            @SuppressWarnings("resource")
            Socket connectionSocket = welcomeSocket.accept();
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
            clientSentence = inFromClient.readLine();
            System.out.println("Received: " + clientSentence);
            capitalizedSentence = clientSentence.toUpperCase() + '\n';
            outToClient.writeBytes(capitalizedSentence);
            outToClient.flush();
        }
    }

    public static void main(String[] args) throws Exception {
        Server.createListener(null);
    }
}

编辑 1: 这个问题背后的原因是,我试图使用相同的服务器代码将数据发送到另一个不受我控制的客户端。在那种情况下,上面的代码只发送第一个 TCP 数据包。我没有在 Wireshark 上看到第二个 TCP 数据包。关于如何调试它有什么建议吗?

最佳答案

据我所知,你不能,更重要的是:你不应该

重点是:那些库打算为您创建一个抽象。 TCP 协议(protocol)实际上复杂;并且最有可能;您不想处理所有细微的细节。

所以这里没有答案:除非你遇到这个实现的真正问题(比如 Not Acceptable 性能损失)——你应该考虑编写清晰、可读的代码;而不是摆弄 TCP 堆栈实现细节!

示例:您的代码不处理异常,您只是让它们通过。您的代码没有关闭流;您的代码包含抑制警告注释。显然:它从未在编写时考虑到单元测试。

这些事情很重要。如果 JVM 发送一个或两个 TCP 包,则不会!

关于java - 为什么 Java writeBytes 在第一个 TCP 数据包中只发送一个字节并保留在另一个 TCP 数据包中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43418015/

相关文章:

c++ - 选择套接字和标准输入

java - Spring XD 使用自定义 TCP 序列化器

java - 未找到 HTTP/1.1 404 - JSON Spring MVC

java - 总重量。标签不可见时不占用空间

将 32 位网络命令转换为 C 中的主机

c - 服务器无法正确读取/打开客户端用 C 发送的文件名

java - 遗传算法适应度分数问题

java - 通过 JavaScript 与 Vaadin 代码处理事件是否有任何服务器负载平衡优势?

postgresql - 尝试在一个连接到另一个容器中的postgres的容器中运行go程序时发生拨号错误(拨号tcp 172.18.0.2:8001:connect:连接被拒绝)

c - 套接字失败后重写