C# TCP 客户端发送但不接收消息

Posted

技术标签:

【中文标题】C# TCP 客户端发送但不接收消息【英文标题】:C# TCP client sending but not receiving messages 【发布时间】:2015-01-08 22:17:16 【问题描述】:

我继承了一些用于 TCP 客户端的代码。它发送一条消息,然后在完成时等待确认消息。目前它发送消息,但是当它等待回复消息时,它永远不会收到它。 SendMessage() 方法是外部调用的。

我设置了断点,可以看到它命中了Receive() 方法,但从来没有命中ReceiveCallback()

感谢您向正确方向提供任何帮助或推动。

public class SocketService

    private ManualResetEvent connectDone = new ManualResetEvent(false);
    private ManualResetEvent sendDone = new ManualResetEvent(false);
    private ManualResetEvent receiveDone = new ManualResetEvent(false);

    string ipAddress;
    private int portNum;
    string returnMessage;
    // private string hostName = Dns.GetHostName ();

    public SocketService(string ipAddress, int portNum)
    
        this.ipAddress = ipAddress;
        this.portNum = portNum;
    

    public event Logging OnLogging;

    private void WriteLogMessage(string message)
    
        if (this.OnLogging != null)
            this.OnLogging(message);
    

    //char endOfLineSeparator = (char) 0x1C;
    //char cr = (char) 0x0D;
    //char vt = (char) 0x0B;

    public string SendMessage(string message)
    
        IPAddress ip = IPAddress.Parse(this.ipAddress);
        IPEndPoint remoteEP = new IPEndPoint(ip, portNum);

        connectDone.Reset();

        Socket client = new Socket(AddressFamily.InterNetwork,
                                    SocketType.Stream,
                                    ProtocolType.Tcp);

        client.BeginConnect(remoteEP,
                            new AsyncCallback(ConnectCallback),
                            client);

        connectDone.WaitOne();

        //sendDone.Reset();

        WriteLogMessage("send message");

        Send(client, message);
        sendDone.WaitOne();

        //receiveDone.Reset();

        WriteLogMessage("receive message");

        Receive(client);
        receiveDone.WaitOne();

        client.Shutdown(SocketShutdown.Both);
        client.Close();

        return this.returnMessage;
    

    private void Send(Socket client, String data)
    
        byte[] byteData = Encoding.ASCII.GetBytes(data);

        client.BeginSend(byteData,
                        0,
                        byteData.Length,
                        0,
                        new AsyncCallback(SendCallback),
                        client);
    

    private void SendCallback(IAsyncResult ar)
    
        Socket client = (Socket)ar.AsyncState;

        int bytesSent = client.EndSend(ar);

        sendDone.Set();
    

    private void ConnectCallback(IAsyncResult ar)
    
        Socket client = (Socket)ar.AsyncState;

        client.EndConnect(ar);

        connectDone.Set();
    

    private void Receive(Socket client)
    
        StateObject state = new StateObject(client);

        client.BeginReceive(state.Buffer,
                            0,
                            StateObject.BufferSize,
                            0,
                            new AsyncCallback(ReceiveCallback),
                            state);
    

    private void ReceiveCallback(IAsyncResult ar)
    
        StateObject state = (StateObject)ar.AsyncState;
        Socket client = state.WorkSocket;

        int bytesRead = client.EndReceive(ar);

        if (bytesRead > 0)
        
            state.StoredContent.Append(Encoding.ASCII.GetString(state.Buffer, 0, bytesRead));

            client.BeginReceive(state.Buffer,
                                0,
                                StateObject.BufferSize,
                                0,
                                new AsyncCallback(ReceiveCallback),
                                state);

            WriteLogMessage(state.StoredContent.ToString());
        
        else
        
            this.returnMessage = state.StoredContent.ToString();

            receiveDone.Set();
        
    

【问题讨论】:

评论你所有的ManualResetEvents 然后再试一次,你得到ReceiveCallback 调用了吗? 根据您在 TCP 上实现的协议,“消息”的定义是什么?对方如何知道它已收到完整的消息,以便知道要响应? 顺便说一句:同步回调不是一件容易的事,我建议使用 awaitable async 方法,如 SendTaskAsyncReceiveTaskAsync 等. 【参考方案1】:

您的SendMessageReceive 函数实际上没有任何作用。他们只是发送和接收字节。他们没有“消息”的概念,在发送消息时不标记消息的结尾,在接收消息时也不识别消息的结尾。简单地说,你忘了实现网络协议,并假设 TCP 是一个消息服务,而实际上它是一个字节流服务。

如果您需要发送和接收消息,您必须准确定义“消息”是什么,并编写代码来发送和接收它们。它不会靠魔法起作用。

【讨论】:

我正在发送一条 HL7 消息并收到一个 ACK​​ 回复。我知道我要发送的内容的开头和结尾字符。我的假设是,当我打开接收器时,我的方向的任何东西都会被它抓住。不是这样吗? 正如我在最初的问题中所说,我继承了这个项目,我不知道套接字的所有技术细节。所以用萨里斯的话来说,“像孩子一样解释”。请。【参考方案2】:

正如 David Schwartz 指出的那样,您需要一种分隔消息的方法。

看看WebSocket data is framed如何。

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

【讨论】:

【参考方案3】:

最终,这是一件没人知道的事情。这些是 HL7 消息,并且缺少消息末尾的隐藏字符。接收方一直在等待消息发送完毕,但是没有这个字符,它就永远看不到完整的消息,因此永远不会发回确认。

【讨论】:

以上是关于C# TCP 客户端发送但不接收消息的主要内容,如果未能解决你的问题,请参考以下文章

C# Async TCP Server 矫枉过正?

TCP c#客户端可以在不休眠的情况下连续/连续接收和发送吗?

TCP客户端(java)没有从TCP服务器(C#)接收消息

Python WebSocket客户端连接但不发送消息

如何在 C# 中使用 TCP 客户端读取整个输入缓冲区?

C#基于UDP实现简单客户端和服务器消息发送和接收