Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用c#套接字的接收短于预期_C#_Sockets - Fatal编程技术网

使用c#套接字的接收短于预期

使用c#套接字的接收短于预期,c#,sockets,C#,Sockets,我使用TCP套接字在项目的两个组件(都在本地运行)之间进行通信。一个充当服务器,处理数据并向另一个发送消息,另一个充当客户端 从服务器发送时,我首先发送一个4字节长的头,然后发送消息: public void SendMessage(string message) { var binaryMessage = Encoding.UTF8.GetBytes(message); var messageLength = binaryMessage.Length; var mess

我使用TCP套接字在项目的两个组件(都在本地运行)之间进行通信。一个充当服务器,处理数据并向另一个发送消息,另一个充当客户端

从服务器发送时,我首先发送一个4字节长的头,然后发送消息:

public void SendMessage(string message) {
    var binaryMessage = Encoding.UTF8.GetBytes(message);
    var messageLength = binaryMessage.Length;
    var messageLengthBytes = BitConverter.GetBytes(messageLength);

    _tcpClient.Client.Send(messageLengthBytes);
    var bytesSent = _tcpClient.Client.Send(binaryMessage);

    if (bytesSent != messageLength) {
        _log.Warn($"Incorrect byte count send ({bytesSent} instead of {messageLength}).");
    }
}
在客户端,当接收时,我读取4个字节以获取长度头,然后读取4KB块直到完成:

private const int RecBufferSize = 4096;
private readonly byte[] _recBuffer = new byte[RecBufferSize];

private void HandleNextIncomingMessage(IAsyncResult ar) {
    var bytesReceived = _tcp.Client.EndReceive(ar);

    if (bytesReceived != 4) {
        _log.Error("Could not figure out the size of the incoming message - forcing reconnect.");
        Reconnect();
        return;
    }

    var array = _recBuffer.Take(4).ToArray();
    var messageSize = BitConverter.ToInt32(array, 0);
    var messageBuffer = new byte[messageSize];
    var totalBytesFedIntoMessageBuffer = 0;

    while (totalBytesFedIntoMessageBuffer < messageSize) {
        var bytesToRead = messageSize - totalBytesFedIntoMessageBuffer;

        if (bytesToRead > RecBufferSize) {
            bytesToRead = RecBufferSize;
        }

        var bytesRead = _tcp.Client.Receive(_recBuffer, bytesToRead, SocketFlags.None);

        if (bytesRead != bytesToRead) {
            _log.Error($"Did not read the correct number of bytes {bytesToRead} from the network - read {bytesRead} - forcing reconnect.");
            Reconnect();
            return;
        }

        Buffer.BlockCopy(_recBuffer, 0, messageBuffer, totalBytesFedIntoMessageBuffer, bytesRead);

        totalBytesFedIntoMessageBuffer += bytesRead;
    }

    HandleMessage(Encoding.UTF8.GetString(messageBuffer));
}
private const int RecBufferSize=4096;
私有只读字节[]u recBuffer=新字节[RecBufferSize];
私有无效句柄消息(IAsyncResult ar){
var bytesserved=_tcp.Client.EndReceive(ar);
如果(字节数已接收!=4){
_错误(“无法计算传入消息的大小-强制重新连接”);
重新连接();
返回;
}
var数组=_recBuffer.Take(4.ToArray();
var messageSize=BitConverter.ToInt32(数组,0);
var messageBuffer=新字节[messageSize];
var totalBytesFedIntoMessageBuffer=0;
while(totalBytesFedIntoMessageBufferRecBufferSize){
bytesToRead=RecBufferSize;
}
var bytesRead=_tcp.Client.Receive(_recBuffer,bytesToRead,SocketFlags.None);
if(bytesRead!=bytesToRead){
_log.Error($“没有从网络读取正确的字节数{bytesToRead},读取{bytesRead},强制重新连接。”);
重新连接();
返回;
}
Buffer.BlockCopy(_recBuffer,0,messageBuffer,totalBytesFedIntoMessageBuffer,bytesRead);
totalBytesFedIntoMessageBuffer+=字节读取;
}
HandleMessage(Encoding.UTF8.GetString(messageBuffer));
}
大多数消息都很小(<1KB),从来不会有任何问题,但有一条消息承载大量数据,大小可能为100-200KB。大多数情况下,发送和接收时都没有问题,但偶尔一个数据块不包含正确的字节数,我看到日志行
没有从网络读取正确的字节数4096-读取3472-强制重新连接。

奇怪的是,这个数字并不总是3472,但经常是


如果我将数据发送到服务器端的套接字中,然后在客户端调用
Receive
,它应该阻塞直到接收到完整的4096字节,这样的想法对吗?如果是这样的话,为什么它有时会收到较少的字节数?

该消息是否记录在最后收到的数据块上?如果有效载荷不是X块那么大,就会发生这种情况,对吗?在这种情况下这不会是一个错误,它只是流的结尾。每个块要读取的字节数是在while块内计算的,因此如果还有>chunksize字节要读取,则取一个块大小(4096),否则取剩余的。我注意到它更多地发生在第一个块上。你应该使用
bytesRead
,而不是将它与请求的计数进行比较。接收少于请求量不是问题,如果已经分配了x字节的messagebuffer,为什么要使用4k的接收缓冲区?使用该缓冲区接收消息。从套接字请求200k不是问题。您可能会收到较少的请求,但它将与下一个请求一起收到。socket.Receive()方法有一个重载,因此您可以传递接收缓冲区的起始偏移量以继续接收。我总是重用接收缓冲区并构造一个类来保存来自它的消息,这样您就可以重用相同的bytebuffer。这会阻止许多分配。(和块拷贝)即使是小到4个字节的读取,为了获得长度,数据可能最终会在数据包边界上碎片化(TCP只传递字节),因此对于所有读取,您应该在循环中读取,并使用返回的值来了解需要多少,而不是试图预先计算并期望返回许多字节。正如Jeroen所说,这个中间固定大小的缓冲区似乎在这里没有任何好处。这个消息记录在最后接收到的数据块上吗?如果有效载荷不是X块那么大,就会发生这种情况,对吗?在这种情况下这不会是一个错误,它只是流的结尾。每个块要读取的字节数是在while块内计算的,因此如果还有>chunksize字节要读取,则取一个块大小(4096),否则取剩余的。我注意到它更多地发生在第一个块上。你应该使用
bytesRead
,而不是将它与请求的计数进行比较。接收少于请求量不是问题,如果已经分配了x字节的messagebuffer,为什么要使用4k的接收缓冲区?使用该缓冲区接收消息。从套接字请求200k不是问题。您可能会收到较少的请求,但它将与下一个请求一起收到。socket.Receive()方法有一个重载,因此您可以传递接收缓冲区的起始偏移量以继续接收。我总是重用接收缓冲区并构造一个类来保存来自它的消息,这样您就可以重用相同的bytebuffer。这会阻止许多分配。(和块拷贝)即使是小到4个字节的读取,为了获得长度,数据可能最终会在数据包边界上碎片化(TCP只传递字节),因此对于所有读取,您应该在循环中读取,并使用返回的值来了解需要多少,而不是试图预先计算并期望返回许多字节。正如Jeroen所说,这种中间固定大小的缓冲区在这里似乎没有任何好处。