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

时间:2014-05-21 13:39:22

标签: c# sockets asynchronous

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

我想将一个对象从服务器传输到客户端。不幸的是,我遇到了问题,有时候这个对象并没有一次完全传输。因此,我需要一种方法来确定对象何时完全传输。所以我在发送的数据中添加了一个四字节的磁头,告诉它将有多长时间。

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

解决方案

感谢 usr 我已将客户端的ReceiveCallbackCode中的bytesRead-Part更改为此。它似乎现在有效。

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

1 个答案:

答案 0 :(得分:2)

您没有使用EndReceivebytesRead)的返回值。它表示收到了多少字节。

如果bytesRead == 0你只是做了什么,这可能不是对已经结束的连接的正确回应。

然后,存在这种不同步的忙循环:

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

这将为每个客户端连接刻录一个CPU核心。必须以不同的方式解决这个问题。