0

在下面的代码状态中,是一个具有属性 msgLength 的对象,它是消息的总长度。msgLength 是消息的前四个字节。当在“快速”成功中收到多条消息时,我在 state.msgLength 属性中得到意外结果。当 state.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);
            }
4

1 回答 1

0

我认为state.socket.BeginReceive被执行了两次。因为当它读取它的标题时,if (state.read < 4)if (state.read < state.msglength)都是 true。在第一个state.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)因为长度标头包含在您的缓冲区中。

我主要是分开阅读标题/数据。喜欢:(伪)

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();
}
于 2013-08-09T07:52:43.500 回答