为什么我的客户端套接字没有收到我的服务器套接字发送的内容? [英] Why does my client socket not receive what my server socket sends?

查看:32
本文介绍了为什么我的客户端套接字没有收到我的服务器套接字发送的内容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using a blocking, streaming .NET socket I'm connecting to a server. Whenever I'm reading small bits of data, all goes well and the data is received into my buffer:

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));
}

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

In some cases though, I'm not receiving everything the server sends me. Data seems to be chopped off. What can be the cause of this?

推荐答案

这是 记录在 Receive() 方法中,强调我的:

This is documented in the Receive() method, emphasis mine:

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

The Receive method reads data into the buffer parameter and returns the number of bytes successfully read. You can call Receive from both connection-oriented and connectionless sockets.

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

When ignoring the return value, you will not know what portion of your buffer actually contains relevant data. Depending on the protocol being used, you may or may not know the content length in advance. Some protocols provide this length, others close the connection when done, yet another can use a message boundary.

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

You'll have to hold the received data in another buffer, and return or output the entire message buffer when no more data is available or expected. This can be done like this:

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 变量.代码循环直到服务器关闭连接.

The received bytes are ASCII characters (as defined in the made-up protocol), so each byte received indicates one character (you can't convert partially received multibyte unicode characters). The bytes are converted to a string and appended to the message variable. The code loops until the server closes the connection.

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

When the message size is known on beforehand, again, depending on the protocol being used, you can create a message buffer and copy the data there on each 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));

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

This can in turn be put in a resuable method:

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 包装了一个套接字,但它 与套接字本身具有相同的读取问题.您必须监视返回值并继续调用 Read() 直到您收到所有字节.TcpClient 有一个 GetStream() 方法,在它的返回值上你也会必须继续阅读,直到读完所有数据.

There's the NetworkStream which wraps a socket, but it has the same reading issues as the socket itself. You will have to monitor the return value and keep calling Read() until you've received all bytes. Same goes for the TcpClient that has a GetStream() method, on whose return value you'll also have to continue reading until you've read all data.

这篇关于为什么我的客户端套接字没有收到我的服务器套接字发送的内容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆