如何正确接收碎片TCP数据?

时间:2017-02-25 23:36:36

标签: c# sockets tcp stream

我尝试通过TCP从网络摄像头发送实时视频流。我在发送前用JPG压缩图像;工作正常。但我的接收器插座有些问题。它不知何故只能在接收方获得四分之一的完整图像。

在解码我收到的字节数组之后看起来像这样:

enter image description here

我还编写了以下代码来接收图像数据(receive在一个帖子中运行):

    private void receive() {
        try {
            while(running) {
                if((available = clientSocket.Receive(buffer, 4, SocketFlags.None)) >= 0) {
                    int bytesToRead = BitConverter.ToInt32(buffer, 0);
                    using(MemoryStream ms = new MemoryStream(bytesToRead)) {
                        using(BinaryWriter bw = new BinaryWriter(ms)) {
                            while(bytesToRead > 0) {
                                if((available = clientSocket.Receive(buffer, getRemainingBytes(bytesToRead), SocketFlags.None)) >= 0) {
                                    bw.Write(buffer);
                                    bytesToRead -= available;
                                }
                            }
                            NetworkPacket.deserialize(ms.ToArray());
                        }
                    }
                }
            }
        } catch(Exception ex) {
            Logger.Log(Level.WARNING, "Could not receive data from TCP server.", ex);
        }
    }

    private int getRemainingBytes(int bytesToRead) {
        if(bytesToRead > clientSocket.ReceiveBufferSize) {
            return clientSocket.ReceiveBufferSize;
        } else {
            return bytesToRead;
        }
    }

你可以猜到,我的消息结构的前4个字节(Int32)定义了我必须为每个图像读取的数据包长度(这些数据在30-40kB之间)。

如果我只用clientSocket.Receive(buffer, 4, SocketFlags.None)读取缓冲数据的前4个字节,那么剩下的数据会在场景后面发生什么?可以在第二次'clientSocket.Receive(...)'调用中读取它们,还是第二次调用'clientSocket.Receive(...)'时第一次调用的剩余字节是否被删除?

如果假设每秒大约30张图像到达每张30-40kB,我怎样才能改进接收器代码?

1 个答案:

答案 0 :(得分:3)

<强> FIX

您应该只“写”您收到的字节

bw.Write(buffer)更改为

bw.Write(buffer, 0, available);

<强>加速比

您可以直接将网络数据读入缓冲区,而不是在多个缓冲区之间移动接收到的数据。

int bytesToRead = BitConverter.ToInt32(buffer, 0);
int offset = 0;
byte[] frame = new byte[bytesToRead];
while (bytesToRead > 0)
{
    var n = clientSocket.Receive(frame, offset, bytesToRead);
    offset += n;
    bytesToRead -= n;
}

NetworkPacket.deserialize(frame);