【问题标题】:Network stream stuck on stream.Read(byte[] byte, int offset, int size)网络流卡在 stream.Read(byte[] byte, int offset, int size)
【发布时间】:2013-09-13 18:07:07
【问题描述】:

我要做的是接收从客户端发送的大量字节(大约5MB数据)

下面是接收data(byte[])的代码

    byte[] receivedBytesRaw = new byte[4000];
 //first, initialize network stream
 NetworkStream stream = client.GetStream();
    //The bytesNeeded is the size of bytes which is a protocol sent by the client side indicating the size of byte which will be sent
    int bytesNeeded = 4000;
    int bytesReceived = 0;
    do
    {
        int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded - bytesReceived);
        networkValidation.addBytesToList(receivedBytesRaw, ref receivedBytes);
        bytesReceived += bytesRead;
    } while (bytesReceived < bytesNeeded);

但现在我遇到了一个问题:

每次数据到达,do while循环第一次循环,返回值(i)为26,然后再次循环,这次到" i = stream.Read(receivedBytesRaw, 0, receivedBytesRaw.Length);"时,程序似乎在等待客户端发送数据没有响应,另外,当我检查“receivedBytesRaw”时,数据不完整,只收到前13个字节,字节数组中剩余空间保持为空,stream.DataAvailable为false

为什么服务器端收到不完整的数据? 注意:当我尝试发送小数据(字符串)时,没关系

================================================ =======================

编辑

下面是发送数据的客户端代码:

   private int sendData(byte[] dataSend, string IP, int portNumber)
    {
        TcpClient clientSide = new TcpClient();
        int result = -1;
        try
        {
            clientSide.Connect(IP, portNumber);
        }
        catch (Exception ex)
        {
            return 2;
        }
        NetworkStream netStream = clientSide.GetStream();
        if (netStream.CanWrite)
        {
            byte[] replyMsg = new byte[1024];

            netStream.Write(dataSend, 0, dataSend.Length);
            netStream.Flush();
            result = 0;
        }
        else
        {
            result = 1;
        }
        return result;
    }

【问题讨论】:

  • 你能把客户端的代码贴出来吗?他们需要同步发送的数据量
  • 请看我编辑的代码,我已经测试了客户端并且发送的数据(字节数组)是正确的
  • 您根本不知道何时停止阅读。 TCP 是流,而不是数据包格式。发送者没有说明它将发送多少字节,也没有关闭套接字。所以接收器将不可避免地陷入循环中。通过首先写入 dataSend.Length 来解决此问题。接收者现在可以先读取它并计算字节数。
  • 我在服务器端做了一个小修改,结果还是一样..
  • @user2191496 你试过 Jeroen van Langen 提供的方法吗?

标签: c# network-programming networkstream


【解决方案1】:

因为它是一个流,并且可以部分接收。你确定你总是收到 te 大小为 2048 字节的包吗?

     int i = 0;
     int bytesNeeded = 200;
     int bytesReceived = 0;
     do
      {
        //read byte from client
        int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded-bytesReceived);
        bytesReceived += bytesRead;
        // merge byte array to another byte array
      } while (bytesReceived < bytesNeeded);

我认为您需要一个帧协议,尝试创建一个协议,例如写入后面的数据大小。

示例:(伪)

void SendData(byte[] data)
{
    // get the 4 bytes of a int value.
    byte[] dataLength = BitConverter.GetBytes(data.Lenght);
    // write the length to the stream.
    stream.Write(dataLength, 0, dataLength.Length);
    // write the data bytes.
    stream.Write(data, 0, data.Length);
}

void Receive()
{
    // read 4 bytes from the stream.
    ReadBuffer(buffer, 4);
    // convert those 4 bytes to an int.
    int dataLength = BitConverter.ToInt32(buffer, 0);
    // read bytes with dataLength as count.
    ReadBuffer(buffer, dataLength);    
}

// read until the right amount of bytes are read.
void ReadBuffer(byte[] buffer, int length)
{
    int i = 0;
    int bytesNeeded = length;
    int bytesReceived = 0;
    do
    {
        //read byte from client
        int bytesRead = stream.Read(buffer, bytesReceived, bytesNeeded-bytesReceived);
        bytesReceived += bytesRead;
        // merge byte array to another byte array
    } while (bytesReceived < bytesNeeded);   //  <- you should do this async.
}

这只是一个例子..

【讨论】:

  • 我试过你的方法,如上面代码所示,但结果还是一样...
【解决方案2】:

您可以尝试的另一个解决方案是使用异步读取。 我创建了一个读取所有字节的类。如果读取完整文件没有问题,您可以尝试以下操作:

例子:

这个例子表明你可以阅读一个简单的协议。 ReadPacket 处理长度 + 数据消息。所以发送者将首先发送一个包含后面数据长度的 int 值。 StartReading 方法读取文件名和文件数据。它将存储高达 10mb 的最大文件大小。但这最初并不是为接收文件而设计的。

const int MaxFileSize = 10 * 1024 * 1024;

private void Example()
{
    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socket.Connect("localhost", 12345);

    StartReading(socket);
}

private void StartReading(Socket socket)
{
    ReadPacket(socket, (filenameData) =>
    {
        if (filenameData.Count == 0)
        {
            // disconnected
            return;
        }

        // parse the filename
        string filename = Encoding.UTF8.GetString(filenameData.Array, filenameData.Offset, filenameData.Count);
        Trace.WriteLine("Receiving file :" + filename);

        ReadPacket(socket, (fileData) =>
        {
            if (fileData.Count == 0)
            {
                // disconnected
                return;
            }

            Trace.WriteLine("Writing file :" + filename);

            // write to the file
            using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
                stream.Write(fileData.Array, fileData.Offset, fileData.Count);

            // start waiting for another packet.
            StartReading(socket);
        });
    });
}

private void ReadPacket(Socket socket, Action<ArraySegment<byte>> endRead)
{
    // read header. (length of data) (4 bytes)
    EasySocketReader.ReadFromSocket(socket, 4, (headerBufferSegment) =>
    {
        // if the ReadFromSocket returns 0, the socket is closed.
        if (headerBufferSegment.Count == 0)
        {
            // disconnected;
            endRead(new ArraySegment<byte>());
            return;
        }

        // Get the length of the data that follows
        int length = BitConverter.ToInt32(headerBufferSegment.Array, headerBufferSegment.Offset);

        // Check the length
        if (length > MaxFileSize)
        {
            // disconnect
            endRead(new ArraySegment<byte>());
            return;
        }

        // Read bytes specified in length.
        EasySocketReader.ReadFromSocket(socket, length, (dataBufferSegment) =>
        {
            // if the ReadFromSocket returns 0, the socket is closed.
            if (dataBufferSegment.Count == 0)
            {
                endRead(new ArraySegment<byte>());
                return;
            }

            endRead(dataBufferSegment);
        });

    });

}

EasySocketReader 类可以在我的博客上找到:http://csharp.vanlangen.biz/network-programming/async-sockets/asyncsocketreader/

原始的 EasyPacketReader 可以在这里找到:http://csharp.vanlangen.biz/network-programming/async-sockets/easypacketreader/

对于发送部分,您可以使用如下内容:

private void SendFile(Socket socket, string filename)
{
    byte[] filenameData = Encoding.UTF8.GetBytes(filename);
    socket.Send(BitConverter.GetBytes(filenameData.Length));
    socket.Send(filenameData);

    int fileSize;
    byte[] fileData;

    using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        fileSize = (int)stream.Length;

        if (fileSize > MaxFileSize)
            throw new ArgumentOutOfRangeException("File too big");

        fileData = new byte[fileSize];

        stream.Read(fileData, 0, fileSize);
    }

    socket.Send(BitConverter.GetBytes(fileSize));
    socket.Send(fileData);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    • 2020-02-03
    相关资源
    最近更新 更多