套接字开始接收回调意外结果

本文关键字:意外 结果 回调 开始 套接字 | 更新日期: 2023-09-27 18:26:54

在下面的代码中,状态是一个对象,其属性msgLength是消息的总长度。msgLength是消息的前四个字节。当"快速"成功接收到多条消息时,我在状态.msgLength属性中得到了意外结果。当状态.msglength不符合预期时我在尝试接收时出错。指定的参数超出了有效值的范围。

              StateObj state = (StateObj)ar.AsyncState;
            try
            {
                state.read += state.socket.EndReceive(ar);
                if (state.read == 0)
                {
                    state.socket.Close();
                    state.socket.Dispose();
                    state.socket = null;
                    this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(DateTime.Now.ToString("HH:mm ss") + " socket closed"); });
                    return;
                }
            }
            catch (Exception)
            {
                this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(DateTime.Now.ToString("HH:mm ss") + " socket closed"); });
                return;
            }
            if (state.read < 4)
            {
                //read again you dont have state,msglength
                state.socket.BeginReceive(state.dataBuffer, state.read, 4 - state.read, 0, cbReceive, state);
            }
            else
            {
                state.msglength = BitConverter.ToInt32(state.dataBuffer, 0);
            }
            if (state.read < state.msglength)
            {
                //read again you dont have the complete message 
                //here is the error Specified argument was out of the range of valid values. 
                state.socket.BeginReceive(state.dataBuffer, state.read, state.msglength - state.read, 0, cbReceive, state);
            }
            else
            {
            //process here
             if (state.read > state.msglength )
                {
                    state.read = state.read - state.msglength;
                }
                else
                {
                    state.read = 0;
                }
                state.socket.BeginReceive(state.dataBuffer, 0, state.dataBuffer.Length, 0, cbReceive, state);
            }

套接字开始接收回调意外结果

我认为state.socket.BeginReceive被执行了两次。因为当它读取它的头时,if(state.read<4)if(state.read<state.msglength)都为true。在第一个状态后返回。socket.BeginReceive(..可以解决问题。

if (state.read < 4)
        {
            //read again you dont have state,msglength
            state.socket.BeginReceive(state.dataBuffer, state.read, 4 - state.read, 0, cbReceive, state);
           return;  //  <------
        }
        else
        {
            state.msglength = BitConverter.ToInt32(state.dataBuffer, 0);
        }
        if (state.read < state.msglength)
        {
            //read again you dont have the complete message 
            //here is the error Specified argument was out of the range of valid values. 
            state.socket.BeginReceive(state.dataBuffer, state.read, state.msglength - state.read, 0, cbReceive, state);
        }
        else
        {
           state.read = 0;
          //process correctly expected message
        }

我想我发现了另一个问题,如果消息中指定的messageLength只是数据的大小。您应该读取if(state.read<state.msglength+4),因为长度标头包含在缓冲区中。

我大部分时间都在阅读标题/数据。类似:(PSEUDO)

byte[] header;
byte[] buffer;
int bytesRead;
public void ReadHeader()
{
    bytesNeeded = 4;
    bytesRead = 0;
    BeginReadHeader();
}
public void BeginReadHeader()
{
    BeginReceive(header, bytesRead, bytesNeeded-bytesRead, EndReadHeader);
}
public void EndReadHeader()
{
    int read = EndReceive();
    if(read == 0)
    {
        CloseSocket();
        return;
    }
    bytesRead += read;
    if(bytesRead == byteNeeded)
        ReadData();
    else
        BeginReadHeader();
}
public void ReadData()
{
    bytesNeeded = BitConverter.ToInt32(header, 0);
    bytesRead = 0;
    if(buffer.Length < bytesNeeded)
        buffer = new byte[bytesNeeded];
    BeginReadData();
}
public void BeginReadData()
{
    BeginReceive(buffer, bytesRead, bytesNeeded-bytesRead, EndReadData);
}
public void EndReadData()
{
    int read = EndReceive();
    if(read == 0)
    {
        CloseSocket();
    }
    bytesRead += read;
    if(bytesRead == byteNeeded)
    {
        HandleData();
    }
    else
        BeginReadData();
}
public void HandleData()
{
     // handle data in buffer. BinaryReader
     ReadHeader();
}