Windows socket.Send 数据直到socket.Close 才被接收

发布于 2024-08-21 20:02:28 字数 2295 浏览 7 评论 0原文

我正在开发一个异步接受 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 返回正确的字节数,但在套接字被释放之前不会收到数据。

欢迎提出建议。

I'm developing a server application that asynchronously accepts TCP connections (BeginAccept/EndAccept) and data (BeginReceive/EndReceive). The protocol requires an ACK to be sent whenever the EOM character is found before it will send the next message. The accept and receive are working but the sending app is not receiving the ACK (sent synchronously).

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

The state.Socket.Send returns the correct number of bytes but the data isn't received until the socket is disposed.

Suggestions are appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦开始←不甜 2024-08-28 20:02:29
  • 您不应该从异步完成例程中同步执行任何操作。在负载下,您最终可能会劫持线程池中的所有 IO 完成线程,并严重损害性能,甚至导致完全 IO 死锁。因此,不要从异步回调同步发送 ACK。
  • 使用前导码的协议和格式比使用终止符的协议和格式更容易管理。 IE。将消息的长度写入固定大小的消息头中,而不是检测终止符 \0x13。当然,如果协议一开始就在您的控制之下,则这适用。

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

  • you shouldn't do anything synchronous from async completion routines. Under load you can end up hijacking all IO completion threads from the thread pool and severly hurt performance, up to and including complete IO deadlock. So don't send ACKs synchronously from async callback.
  • protocols and formats that use preambles are easier to manage that those that use terminators. Ie. write the length of the message in the fixed size message header as opposed to detecting a terminator \0x13. Of course, this applies if the protocol is under your control to start with.

As for your question, you didn't specify if the same code as you posted is also on the client side too.

一杆小烟枪 2024-08-28 20:02:29

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

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

您可能想尝试使用 IOControl< /a> 方法。

编辑

实际上,IOControl刷新会杀死缓冲区。您可能需要查看两位将军问题,看看您的协议是否会存在一些问题固有的问题。

How long are you giving it? The network stack can buffer, and that could delay transmition. From MSDN:

To increase network efficiency, the
underlying system may delay
transmission until a significant
amount of outgoing data is collected.
A successful completion of the Send
method means that the underlying
system has had room to buffer your
data for a network send.

You might want to try flushing using the IOControl method.

edit

Actually, the IOControl flush will kill the buffer. You may want to check out the Two Generals Problem to see if your protocol will have some inherent problems.

对你再特殊 2024-08-28 20:02:29

尝试设置 TCP_NODELAY 套接字选项

try setting TCP_NODELAY socket option

枕头说它不想醒 2024-08-28 20:02:29

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

Have you set the NoDelay property on the socket to true? When set to false (the default), data is buffered for up to 200 milliseconds before it's sent. The reason is to reduce network traffic by limiting the number of packets that are sent. Setting NoDelay to true will force the data to be sent sooner.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文