确定套接字流中的消息结束

本文关键字:消息 结束 套接字 | 更新日期: 2023-09-27 18:04:31

我有一个使用异步套接字连接的服务器和客户端的项目。

我想发送一个对象从服务器到客户端。不幸的是,我有一个问题,有时物体不能一次完全传输。因此,我需要一种方法来确定一个对象何时被完全传输。因此,我在传输的数据中添加了一个四字节头,以告知流将有多长。

Server
private void Send(Socket handler, Packet packet)
    {
        byte[] byteData = ByteHelper.Serialize(packet).Data;
        byte[] byteDataLength = BitConverter.GetBytes(byteData.Length);
        byte[] transmissionData = new byte[byteDataLength.Length + byteData.Length];
        byteDataLength.CopyTo(transmissionData, 0);
        byteData.CopyTo(transmissionData, byteDataLength.Length);
        if (debug)
        {
            Status = "Sending "+packet.Type+"-packet to client.";
        }
        try
        {
            handler.BeginSend(transmissionData, 0, transmissionData.Length, 0, new AsyncCallback(SendCallback), handler);
        }
        catch (Exception ex)
        {
            Status = "[EXCEPTION]" + ex.Message.ToString();
        }
    }

客户端接收流并计算前四个字节以创建具有正确大小的StateObject。但我有一种感觉,这并不是解决我问题的好方法。有更好的方法吗?

Client
private void ReceiveCallback(IAsyncResult ar)
    {
        StateObject state = (StateObject)ar.AsyncState;
        try
        {
            Socket client = state.workSocket;
            int bytesRead = client.EndReceive(ar);
            if (bytesRead > 0)
            {
                do
                {
                    state = AdjustState(state);
                    if (state != null)
                    {
                        if (state.buffer.Length == state.bufferSize)
                        {
                            ProcessPacket(state);
                            receiveDone.Set();
                        }
                    }
                    else
                    {
                        receiveDone.Set();
                    }
                }
                while (state != null && state.tempBuffer.Length >= state.bufferSize);
                if (state != null)
                {
                    client.BeginReceive(state.tempBuffer, 0, state.tempBuffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("ReceiveCallback: " + ex.ToString(), "Client-Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
private static StateObject AdjustState(StateObject state)
    {
        StateObject tempState = state;
        if (tempState.tempBuffer.Length >= 4)
        {
            byte[] sizeBytes = tempState.tempBuffer.Take(4).ToArray();
            int bufferSize = BitConverter.ToInt32(sizeBytes, 0);
            if (bufferSize == 0)
            {
                return null;
            }
            byte[] temp = tempState.tempBuffer.Skip(4).ToArray();
            Socket tempSocket = tempState.workSocket;
            tempState = new StateObject(bufferSize);
            tempState.BufferSet();
            if (temp.Length >= bufferSize)
            {
                tempState.buffer = temp.Take(bufferSize).ToArray();
                tempState.tempBuffer = temp.Skip(bufferSize).ToArray();
            }
            tempState.workSocket = tempSocket;
        }
        return tempState;
    }
<<p> 解决方案/strong>

多亏了usr我已经把客户端的ReceiveCallbackCode中的bytesread部分改成了这个。现在似乎可以了。

if (bytesRead > 0)
            {
                if (!state.bufferSet)
                {
                    state = AdjustState(state);
                    client.BeginReceive(state.buffer, 0, state.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                }
                else
                {
                    if (state.buffer.Length == state.bufferSize)
                    {
                        ProcessPacket(state);
                        receiveDone.Set();
                    }
                    else
                    {
                        client.BeginReceive(state.buffer, state.buffer.Length, state.bufferSize - state.buffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
                    }
                }
            }

确定套接字流中的消息结束

您没有使用EndReceive (bytesRead)的返回值。它表示接收了多少字节。

bytesRead == 0的情况下,你只是什么也不做,这可能不是一个正确的响应连接已经结束。

然后是这个不同步的忙循环:

while (state != null && state.tempBuffer.Length >= state.bufferSize);

这将为每个客户端连接消耗一个CPU核心。