【发布时间】:2021-12-16 11:21:25
【问题描述】:
有多个帖子描述了保持 TCP 连接打开而不是在每次需要读取或写入时关闭和打开的性能优势。例如:
Best practice: Keep TCP/IP connection open or close it after each transfer?
我正在与基于 RPC 的设备进行通信,该设备采用 json 命令。我从设备供应商那里获得的示例每次发送命令时都会打开和关闭连接。这是我目前在 using 语句中通过 TcpClient 所做的,但我想看看是否有什么可以改进我已经完成的工作。事实上,我在开始项目时曾尝试过此操作,但不知道如何操作,因此每次都出于沮丧和必要性而关闭。我最近使用套接字的实验,因为所有帖子都表明这样做是较低级别控制的必要条件:
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() 中的 Send 上调用了 socket.Shutdown()。我这样做是因为这篇文章:
但是,似乎没有办法在调用 Shutdown() 后重新启用发送功能。所以现在我只是不知道如果你必须读写,是否有可能保持 tcp 连接打开。此外,我在网上真的找不到有用的例子。有谁知道如何在.NET 中这样做?这甚至可能吗?
【问题讨论】:
-
为什么您认为保持连接打开是一种改进?除非您可以指出确实需要这样做,否则它很可能不会有所改进,并且您可能会无缘无故地浪费大量时间。您也很有可能在部署中遇到问题,您不知道如何足够快地修复。你知道有问题的协议是否被设计成这样使用吗?如果没有,你可能会自找麻烦。
-
最终,我正在使用的设备将被整合到制造环境中,用于其他设备的工厂生产。制造设备的速度与制造的经济性直接相关,并且这些类型的系统是在线的并且可以长时间不间断地运行。因此,任何类型的性能提升(我假设是在打开和关闭连接的情况下的执行速度)都是可取的。但我开始意识到,我可能只需要每次打开和关闭一个连接。
-
小公司发布的基于 TCP 的协议存在无可救药的缺陷,并且存在固有的性能问题,这种情况非常普遍。如果这里也出现这种情况,那么保持连接打开不会解决问题。在这种情况下,解决方案是要求创建者修复协议。
-
有缺陷的协议的正常问题是它们依赖于客户端来打开、发送和关闭,或者打开、接收和关闭。由于 TCP 是流而不是数据包,因此它不起作用。您可能会错过数据,或者更糟糕的是,您的速度会变慢。我不会解释为什么。客户端至少应该打开、发送、接收和关闭。你的协议是这样做的吗?如果是的话,太好了!双方都必须知道预期有多少,并继续阅读,可能不止一次,直到收到预期的所有内容。期望多少通常由标头中的长度字段或文本协议中的文本标记(例如 eol)给出。
-
我不是 TCP 专家,尽管我在创建协议和解决问题方面拥有丰富的经验。如果有人看到纠正我的解释的理由,请这样做。