Windows socket。直到socket.Close才接收发送数据

时间:2010-02-15 21:42:14

标签: c# .net sockets send

我正在开发一个异步接受TCP连接(BeginAccept / EndAccept)和数据(BeginReceive / EndReceive)的服务器应用程序。该协议要求在发送EOM字符之前发送ACK,然后才能发送下一条消息。接受和接收正在工作,但发送应用程序没有收到ACK(同步发送)。

    private void _receiveTransfer(IAsyncResult result)
    {
        SocketState state = result.AsyncState as SocketState;
        int bytesReceived = state.Socket.EndReceive(result);

        if (bytesReceived == 0)
        {
            state.Socket.Close();
            return;
        }

        state.Offset += bytesReceived;
        state.Stream.Write(state.Buffer, 0, bytesReceived);

        if (state.Buffer[bytesReceived - 1] == 13)
        {
            // process message
            Messages.IMessage message = null;
            try
            {
                var value = state.Stream.ToArray();

                // do some work
                var completed = true;

                if (completed)
                {
                    // send positive ACK
                    var ackMessage = string.Format(ack, message.TimeStamp.ToString("yyyyMMddhhmm"), message.MessageType, message.Id, "AA", message.Id);
                    var buffer = ASCIIEncoding.ASCII.GetBytes(ackMessage);
                    int bytesSent = state.Socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
                }
                else
                {
                    // send rejected ACK
                    var ackMessage = string.Format(ack, message.TimeStamp.ToString("yyyyMMddhhmm"), message.MessageType, message.Id, "AR", message.Id);
                    state.Socket.Send(ASCIIEncoding.ASCII.GetBytes(ackMessage));
                }
            }
            catch (Exception e)
            {
                // log exception


                // send error ACK
                if (message != null)
                {
                    var ackMessage = string.Format(ack, DateTime.Now.ToString("yyyyMMddhhmm"), message.MessageType, message.Id, "AE", message.Id);
                    state.Socket.Send(ASCIIEncoding.ASCII.GetBytes(ackMessage));
                }
            }
        }

        state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(_receiveTransfer), state);
    }

state.Socket.Send返回正确的字节数,但在放置套接字之前不会收到数据。

建议表示赞赏。

4 个答案:

答案 0 :(得分:2)

  • 您不应该从异步完成例程同步执行任何操作。在负载下,您最终可能会从线程池中劫持所有IO完成线程并严重损害性能,直至并包括完整的IO死锁。所以不要从异步回调中同步发送ACK。
  • 使用前导码的协议和格式比使用终结符的协议和格式更容易管理。 IE浏览器。在固定大小的消息头中写入消息的长度,而不是检测终结符\ 0x13。当然,如果协议在您的控制之下,这适用于此。

至于您的问题,您没有指定您发布的代码是否也在客户端。

答案 1 :(得分:0)

你给它多久了?网络堆栈可以缓冲,这可能会延迟传输。来自MSDN

  

为了提高网络效率,   基础系统可能会延迟   传输直到显着   收集的传出数据量。   成功完成发送   方法意味着底层   系统有空间缓冲你的   网络发送的数据。

您可能想尝试使用IOControl方法进行刷新。

修改

实际上,IOControl flush会杀死缓冲区。您可能需要查看Two Generals Problem以查看您的协议是否存在一些固有问题。

答案 2 :(得分:0)

尝试设置TCP_NODELAY套接字选项

答案 3 :(得分:0)

您是否已将套接字上的NoDelay属性设置为true?设置为false(默认值)时,数据在发送之前最多缓冲200毫秒。原因是通过限制发送的数据包数量来减少网络流量。将NoDelay设置为true会强制更快地发送数据。