我有这个TcpClient代码,工作正常 . 它连接到Linux系统上的perl服务器,并接收服务器发送给它的任何东西 . 很好地工作 .
public static void Main() {
foreach (ProtocolConnection tcpConnection in TcpConnectionsList) {
ProtocolConnection connection = tcpConnection;
ThreadPool.QueueUserWorkItem(_ => {
ThreadTcpClient(connection);
ManualResetEventTcp.Set();
});
}
... Some code...
}
public static void TcpConnect(ProtocolConnection varConnection) {
int retryCountSeconds = varConnection.RetryEverySeconds*Program.MilisecondsMultiplier;
int count = 0;
while (true) {
try {
using (var client = new TcpClient(varConnection.IpAddress.ToString(), varConnection.Port) { NoDelay = true })
using (var stream = client.GetStream()) {
var data = new Byte[256];
while (!Program.PrepareExit) {
Int32 bytes = stream.Read(data, 0, data.Length);
string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();
if (varReadData != "" && varReadData != "PONG") {
VerificationQueue.EnqueueData(varReadData);
Logging.AddToLog("[TCP][" + varConnection.Name + "][DATA ARRIVED]" + varReadData);
} else {
Logging.AddToLog("[TCP]" + varReadData);
}
}
}
} catch (Exception e) {
if (e.ToString().Contains("No connection could be made because the target machine actively refused it")) {
Logging.AddToLog("[TCP][ERROR] Can't connect to server (" + varConnection.Name + ") " + varConnection.IpAddress + ":" + varConnection.Port );
} else {
Logging.AddToLog(e.ToString());
}
}
DateTime startTimeFunction = DateTime.Now;
do {
Thread.Sleep(1000);
} while (((DateTime.Now - startTimeFunction).TotalSeconds < retryCountSeconds));
}
}
但是在某些条件下我遇到了一些问题:
-
我的工作连接经常在一些空闲时间之后断开连接,所以我在服务器中实现了所以当它收到PING时它会以PONG响应 . 我可以用服务器发送带有UDP的PING,它会在tcp上用PONG响应,但我更喜欢内置的方式进入tcp客户端,所以它每60秒左右发送一次PING . 即使UDP解决方案是可以接受的,我在
string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();
也没有超时,所以当PONG甚至没有注意到它时 . 它只是在等待...这让我... -
我的另一个问题是,在某些时候
string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();
这一直在等待数据 . 当服务器崩溃或断开我的客户端时,我甚至都没有注意到 . 我希望服务器有某种timeout
或检查连接是否有效 . 如果它不活动,它应该尝试重新连接 .
修复此TcpClient最简单的方法是什么?我如何实现双向通信,确保如果服务器丢失我的连接或我的网络断开客户端将注意到它并重新 Build 连接?
2 回答
永远不会阻止
Encoding.ASCII.GetString(data, 0, bytes).Trim();
,这是stream.Read()
如果您轻松区分服务器(或其间的任何NAT网关)丢弃连接,以及服务器在发生故障时无法到达您的客户端的情况,或者NAT网关静默地丢弃您的连接 .你可以做什么;
设置发送/ ReceiveTimeout,如果发生超时则ping服务器,或通过TCP连接实现自己的心跳消息 . 如果您在合理的时间内没有收到心跳,请重新 Build 或采取其他措施 .
设置TCP keepalive选项,并依赖它来告诉您服务器是否已经消失 . 见代码here .
最后一点将告诉您tcp连接是否失败,它不会告诉您服务器是否有一些失败 - 例如如果你对你的perl服务器进行CTRL Z,它就会在tcp窗口关闭的情况下不做任何事情,所以如果你需要,你可能需要实现自己的热备份来覆盖这样的情况 .
您应该摆脱UDP心跳尝试并输入real TCP heartbeat . "Pinging"使用UDP的服务器几乎没有意义 .
您的协议也缺失message framing .
仔细阅读这两个链接文章(特别是消息框架) . 您目前使用的协议确实需要严格修改 .