如何在 C# .NET 中保持 TCP 连接打开并执行多个 Writes/Reads?

How to keep a TCP connection open and perform multiple Writes/Reads in C# .NET?

有多个 post 描述了保持 TCP 连接打开而不是每次需要读取或写入时关闭和打开的性能优势。例如:

Best practice: Keep TCP/IP connection open or close it after each transfer?

我正在与接受 json 命令的基于 RPC 的设备通信。我从设备供应商那里得到的例子每次发送命令时都会打开和关闭连接。这是我目前在 using 语句中通过 TcpClient 所做的,但我想看看我是否可以改进我已经完成的工作。事实上,我在开始这个项目时曾尝试过这样做,但不知道该怎么做,所以每次都出于挫败感和必要性而关闭。我最近使用套接字进行的实验是因为所有 post 都表明这样做是较低级别控制的必要条件:

public class Connection
{
    private Socket tcpSocket = null;
    public string IpAddress = "192.168.0.30";
    public int Port = 50002;

    public Connection(string ipAddress, int port)
    {
        this.IpAddress = ipAddress;
        this.Port = port;
    }

    public void Connect()
    {
        DnsEndPoint ipe = new DnsEndPoint(this.IpAddress, this.Port);
        Socket tempSocket =
            new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        tempSocket.Connect(ipe);
        if (tempSocket.Connected)
        {
            this.tcpSocket = tempSocket;
            this.tcpSocket.NoDelay = true;
            this.tcpSocket.
            //this.tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive,true);
            Console.WriteLine("Successfully connected.");
        }
        else
        {
            Console.WriteLine("Error.");
        }

    }

    public void Disconnect()
    {
        this.tcpSocket.Disconnect(true);
        this.tcpSocket.Dispose();
        Console.WriteLine("Successfuly closed.");
    }

    public string SendCommand()
    {
        string path = @"C:\Users\me\Desktop\request.json";
        string request = File.ReadAllText(path);
        Byte[] bytesSent = Encoding.UTF8.GetBytes(request);
        this.tcpSocket.Send(bytesSent);
        this.tcpSocket.Shutdown(SocketShutdown.Send);
        var respBytes = ReceiveAll();
        string s = System.Text.Encoding.UTF8.GetString(respBytes, 0, respBytes.Length);
        return s;
    }

    public byte[] ReceiveAll()
    {
        var buffer = new List<byte>();
        var currByte = new Byte[1];
        var byteCounter = this.tcpSocket.Receive(currByte, currByte.Length, SocketFlags.None);
        while (this.tcpSocket.Available > 0)
        {
            currByte = new Byte[1];
            byteCounter = this.tcpSocket.Receive(currByte, currByte.Length, SocketFlags.None);
            if (byteCounter.Equals(1))
            {
                buffer.Add(currByte[0]);
            }
        }

        return buffer.ToArray();
    }

}

控制台应用程序:

    static void Main(string[] args)
    {
        Connection s = new Connection();
        s.Connect();
        Console.WriteLine(s.SendCommand());
        Console.WriteLine(s.SendCommand());
        Thread.Sleep(5000);
        s.Disconnect();
        Console.ReadKey();
    }

这种方法只管用一次。我第一次调用发送命令。它不是第二次(抛出异常),因为我在 SendCommand() 中调用 socket.Shutdown() on Send。我这样做是因为 post:

TCPClient not receiving data

但是,似乎没有办法在调用 Shutdown() 后重新启用发送功能。所以现在我只是不知道如果你必须读写,是否有可能保持 tcp 连接打开。而且,我真的无法在网上找到有用的示例。有谁知道如何在 .NET 中这样做?这甚至可能吗?

是否可以为更多消息保持连接打开取决于应用程序协议。如果协议不支持,则无法强制执行此操作。因此,请询问供应商或查看协议规范(如果存在)以了解是否支持以及如何支持。

However, there doesn't seem to be a way to re-enable the ability to Send after calling Shutdown().

没有办法。 TCP write shutdown 意味着不想再发送任何信息。这是不可能收回的。如果协议支持多个消息交换,那么它需要有一种不同于调用 Shutdown 的方法来检测消息的结束。

TCP/IP 是一种流媒体协议。要使用它传递消息,您需要一个“框架协议”,以便对等方可以确定消息何时完成。

发出消息结束信号的一种简单方法是在发送完最后一个字节后关闭套接字。但这会阻止套接字重用。有关此示例,请参阅 HTTP 的演变。

如果您的设备就是这样做的,则无法重复使用套接字。