当前位置: 首页 > 知识库问答 >
问题:

Java DataOutputStream不会写入所有消息(TCP套接字)

马冯浩
2023-03-14

在我的客户端服务器应用程序中,我发现了一个奇怪的错误。我得到了以下方法:

sendLoginResponse();
sendPlayerList();
sendCurrentLevelState();

每个方法向客户端发送一个字节数组

如果我只调用其中的2个,一切都正常,客户端会得到所有发送的字节数组。但是如果我调用所有3个,只有第一个和第二个到达客户端,以下方法的顺序并不重要。但是服务器说它们都是发送的。使用写入(byte[]b,int off,int len);方法向客户端iam写入包中的所有长度也是有意义的。奇怪的一点来了:

如果我添加一个线程。睡眠(1000) 在第二种方法之后,第三种方法现在确实在睡眠后到达客户机。我还尝试在每次写调用后刷新DataOutputStream,但这没有帮助。

编辑:

假设我发送了3个登录响应

方法是给我字节[]:

public byte[] getLoginResponse(int playerID){
    byte[] msg = new byte[4];
    short shortMsgLength = 4;
    byte[] msgLength = shortToBytes(shortMsgLength);
    msg[0] = 2;
    msg[1] = msgLength[0];
    msg[2] = msgLength[1];
    msg[3] = (byte) playerID;
    return msg;
}

private byte[] shortToBytes(short value) {
    byte[] returnByteArray = new byte[2];
    returnByteArray[0] = (byte) (value & 0xff);
    returnByteArray[1] = (byte) ((value >>> 8) & 0xff);
    return returnByteArray;
}

以及发送方法:

private void sendLoginResponse() {
    try{
        byte[] msg = rfcObject.getLoginResponse(playerID);
        out.write(msg,0,msg.length);
    }catch(Exception e){
        System.err.println(e.getMessage());
        System.exit(0);
    }
}

因此,如果我连续调用sendLogin响应();三次,客户端只收到2个字节数组,但是服务器说它已经发送了3次

Thread.sleep(1000); `after the second Method-Call, everything works fine..`

读取消息的客户端在线程中运行:

public void run(){
    while(true){
        try {
            byte[] data = new byte[MAX_DATA_SIZE]; // MAX_DATA = 255
            byteCount = in.read(data);

        } catch (IOException ex) {
            handleExceptionError(ex);
        }
    }
}

非常感谢。


共有2个答案

夏理
2023-03-14

和TCP不会丢失数据。

正如在这种性质的问题中几乎无一例外地看到的那样,问题在接受端。您可能假设'read()'填充了缓冲区,而忽略了它返回的计数。

根据您在注释中的协议描述,您应该在这种情况下使用DataInputStream.readFully()

byte type = din,readByte();
int length = din.readShort();
byte[] data = new byte[length];
din.readFully(data);
缪远航
2023-03-14

如果我调用sendLoginResponse();连续三次,客户端只接收2字节数组,但服务器表示已发送了3次。

这是因为TCP是一种面向流的协议。这意味着它不知道或不关心你的消息是如何被分隔的。TCP中没有单独消息的概念,只有字节流,保证字节顺序保持不变。

因此,当发送方调用三个write时,三字节数组通过连接简单地连接起来,并以相同的顺序到达接收方,但接收方不一定需要三个read来获取所有字节,即使需要三个read读取不一定会为每个相应的写入提供相同的字节数组。

您的消息已经具有从字节流获取单个消息的必要信息:

// Client code for reading individual messages from a TCP connection

byte type = din.readByte();

// Read the message length, little-endian.
// We cannot use din.readShort because it's big-endian
int lenLo = din.read();
int lenHi = din.read();
short len = (short)(lenLo | (lenHi << 8));
byte [] body = new byte[len];
din.readFully(body);
 类似资料:
  • 问题内容: 我的GO版本是1.1.1 连接关闭后服务器收到的消息,但设置了NoDelay。 有什么不对 问题答案: 您的代码似乎没有任何根本性的错误,因此我猜错误是在服务器端。 如果在端口5432上创建本地TCP服务器,则可以对此进行测试。 尝试运行下面的服务器代码,然后针对它测试客户端代码。它只是将所有接收到的数据回显到stdout。 按下回车键后,您应该看到发送给客户端的每一行都已打印(没有换

  • 问题内容: 我的插座似乎有问题。在下面,您将看到一些分叉服务器和客户端的代码。服务器打开一个TCP套接字,客户端连接到它,然后关闭它。睡眠用于协调时间。在客户端close()之后,服务器尝试将write()写入其自己的TCP连接的末端。根据write(2)手册页,这 应该 给我一个SIGPIPE和一个EPIPE errno。但是,我看不到。从服务器的角度来看,写入本地关闭的套接字 成功 ,并且没有

  • 我有这个tcp插座 接受一条消息,将其转换为字符串并显示它,但是如果连接没有被客户端关闭,我就不能像预期的那样看到服务器上显示的消息 如何在不需要关闭客户端连接的情况下(由客户端)从客户端发送多条消息? 这里是NodeJs中的客户端 谢谢valeriano cossu

  • 我在Java中编写了一个更新由制表符分隔的文本文件的方法。我正在使用opencsv库。首先我在现有文件中读取,然后我更改一些列的值,然后我覆盖文件。我正在运行Windows 7。现在的问题是,并非所有内容都写入文件。即使我不更改任何值,只是覆盖文件,也不是所有记录都写入。 我的代码如下。它有什么问题?

  • 我正在尝试实现一个简单的actor,它将使用akka zeromq从zeromq接收消息。 系统只打印 发送消息是通过一个简单的python完成的 我注意到的另一件奇怪的事情是,按下enter键后,程序不会终止。如果我使用python脚本向它发送一条消息,它将被激活。以下是完整的输出: 使用 是版本(在Arch Linux上) 这是

  • Netty TCP Server在端口处运行,接收格式的数据。它使用Marine API库将胡言乱语转换为需要从套接字输入流的有意义的信息。 如何获得正在使用的netty服务器端口的输入流?