【问题标题】:Why does my client socket not receive what my server socket sends?为什么我的客户端套接字没有收到我的服务器套接字发送的内容?
【发布时间】:2014-07-05 23:48:14
【问题描述】:

使用阻塞流式.NET socket 我正在连接到服务器。每当我读取少量数据时,一切顺利,数据被接收到我的缓冲区中:

using (var socket = new Socket(SocketType.Stream, ProtocolType.IP))
{
    socket.Connect(IPAddress.Parse("127.0.0.1"), 5000);

    byte[] buffer = new byte[BufferSize];

    socket.Receive(buffer);

    // Here buffer doesn't always contain all data the server sent me?
    Console.WriteLine(Encoding.Default.GetString(buffer));
}

但在某些情况下,我没有收到服务器发送给我的所有内容。数据似乎被切断了。这可能是什么原因?

【问题讨论】:

  • 这是一个参考问题,用于关闭看起来相似的重复问题。请评论或提出改进建议,或用替代方案回答。

标签: .net sockets


【解决方案1】:

这是documented in the Receive() method,强调我的:

Receive 方法将数据读入缓冲区参数并返回成功读取的字节数。您可以从面向连接的套接字和无连接套接字调用 Receive。

忽略返回值时,您将不知道缓冲区的哪一部分实际包含相关数据。根据所使用的协议,您可能会或可能不会提前知道内容长度。一些协议提供此长度,其他协议在完成后关闭连接,还有一些协议可以使用消息边界。

您必须将接收到的数据保存在另一个缓冲区中,并在没有更多可用或预期数据时返回或输出整个消息缓冲区。可以这样完成:

int BufferSize = 1024;

using (var socket = new Socket(SocketType.Stream, ProtocolType.IP))
{
    socket.Connect(IPAddress.Parse("127.0.0.1"), 5000);

    byte[] buffer = new byte[BufferSize];
    string message = "";

    int bytesReceived;
    do
    {
        bytesReceived = socket.Receive(buffer);
        message += Encoding.ASCII.GetString(buffer, 0, bytesReceived);

    } while (bytesReceived > 0);

    Console.WriteLine(message);
}

接收到的字节是 ASCII 字符(在组成的协议中定义),因此接收到的每个字节都表示一个字符(不能转换部分接收到的多字节 unicode 字符)。字节被转换为字符串并附加到message 变量中。代码循环,直到服务器关闭连接。

当事先知道消息大小时,再次,根据所使用的协议,您可以创建一个消息缓冲区并将数据复制到每个Receive()

// Received using another Receive() call
int messageSize = 1234;
int totalBytesReceived = 0;
byte[] messageBuffer = new byte[messageSize];

byte[] buffer = new byte[BufferSize];

int bytesReceived;
do
{
    bytesReceived = socket.Receive(buffer);

    // Copy the receive buffer into the message buffer, appending after 
    // previously received data (totalBytesReceived).
    Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived);
    totalBytesReceived += bytesReceived;

} while (bytesReceived > 0);

// This assumes the connection wasn't closed prematurely.
Console.WriteLine(Encoding.ASCII.GetString(messageBuffer));

这又可以放在一个可重复使用的方法中:

public byte[] ReceiveMessage(Socket socket, int messageSize)
{
    byte[] messageBuffer = new byte[messageSize];

    int bytesReceived = 0;
    int totalBytesReceived = 0;
    do
    {
        byte[] buffer = new byte[BufferSize];

        // Receive at most the requested number of bytes, or the amount the 
        // buffer can hold, whichever is smaller.
        int toReceive = Math.Min(messageSize - totalBytesReceived, BufferSize);
        bytesReceived = socket.Receive(buffer, toReceive, SocketFlags.None);

        // Copy the receive buffer into the message buffer, appending after 
        // previously received data (totalBytesReceived).
        Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived);

        totalBytesReceived += bytesReceived;

    } while (bytesReceived > 0);

    if (totalBytesReceived < messageSize)
    {
        throw new Exception("Server closed connection prematurely");
    }

    return messageBuffer;
}

NetworkStream 包装了一个套接字,但它 has the same reading issues 作为套接字本身。您必须监控返回值并继续调用Read(),直到您收到所有字节。 TcpClient that has a GetStream() method 也是如此,您还将在其返回值上 have to continue reading until you've read all data

【讨论】:

    猜你喜欢
    • 2017-01-04
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多