[英]C# Doing retry on tcp socket communication
如果客戶端無法連接到服務器,我正在嘗試重試編碼。 以下是我的方法:
在主要功能中:
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
ConnectCallback:
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
_logger.Info("## Connection to server successful at " + strServerIP + ":" + strServerPort);
}
catch (Exception ex)
{
_logger.Info("## Connection to server failed. Retrying...");
Socket client = (Socket)ar.AsyncState;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(strServerIP), Convert.ToInt32(strServerPort));
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
}
}
當連接失敗並重試時,我將在ConnectCallback中捕獲異常。
但是我發現,如果重試10次,則在服務器啟動時,該服務器將從同一客戶端獲得10個連接。 如果重試50次,則服務器啟動后,服務器將獲得50個連接。
我的編碼有問題嗎? 似乎每次重試時,我的服務器都會獲得一個新的連接。
沒有有效的示例,很難知道。 如果這與您的實際操作很接近,我懷疑有幾件事是錯誤的。 默認情況下,Socket對象似乎處於阻塞狀態,但是某些東西正在生成您的異常,並且可能與您想像的不一樣。 首先要做的只是捕獲SocketException,然后僅在異常表示可能表明重試有效的情況下重試。 請延遲一下,因為如果1毫秒前它不起作用,則可能現在不起作用。 放置一個衛生狀況計數器,這樣它就可以放棄經過多次嘗試的重試。 檢查您的協議,以確保您向服務器發送了期望的協議。 首先,關閉插座。
我懷疑您看到的是一堆由異常引起的套接字連接(該異常可能與套接字相關,也可能與套接字無關)。 由於您從不關閉它們,它們只會堆積。 我懷疑最終GC可能會啟動並在對象上運行終結器,然后這些終結器將斷開它們的連接。 服務器更有可能斷開連接。 無論哪種方式,如果您沒有顯式關閉Socket,它都會一直掛到發生超時為止。
這是一個工作示例,演示了我認為您要問的問題。 同樣,您需要決定在什么條件下應該重試,因為如果出現任何問題,請重試是不好的。 這可能會導致程序不斷攪動線程,甚至可能攪動連接。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Microsoft.Extensions.Logging;
namespace socketTst {
class Program {
static ILoggerFactory loggerFactory = new LoggerFactory().AddConsole().AddDebug();
static ILogger _logger;
static AutoResetEvent finish = new AutoResetEvent(false);
static String Hostname = "www.google.com";
static int Port = 80;
static int RetryCount = 0;
static void ConnectCallback(IAsyncResult ar) {
_logger.LogInformation($"## ConnectCallback entered");
// Retrieve the socket from the state object.
Socket client = (Socket) ar.AsyncState;
try {
// Complete the connection.
client.EndConnect(ar);
var s = new byte[] { 1 };
client.Send(s);
var buf = new byte[1024];
var cnt = client.Receive(buf);
_logger.LogInformation($"## Connection to server successful at {client.RemoteEndPoint}");
if (cnt > 0) {
var returned = Encoding.UTF8.GetString(buf, 0, cnt);
_logger.LogInformation($"## Data returned: {returned}");
}
else {
_logger.LogInformation($"## No data returned");
}
finish.Set(); // signal end of program
}
catch (SocketException sockExcep) {
_logger.LogInformation($"## Exception: {sockExcep.Message}");
_logger.LogInformation("## Connection to server failed. Retrying...");
// This is a bad idea. You don't know what is wrong so retrying might not be useful.
// What if this is an unknown host or some other error that isn't likely to be
// resolved by a retry ???
RetryCount++;
if (RetryCount > 10) {
_logger.LogInformation("## Not able to reach host after 10 tries");
finish.Set(); // signal end of program
return; // give up
}
Thread.Sleep(797); // wait a bit
var dest = new DnsEndPoint(Hostname, Port);
client.BeginConnect(dest, new AsyncCallback(ConnectCallback), client);
}
catch (Exception ex) {
_logger.LogInformation($"## Exception: {ex.Message}");
}
_logger.LogInformation($"## ConnectCallback exited");
}
static void Main(string[] args) {
_logger = loggerFactory.CreateLogger<Program>();
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Blocking = true;
var dest = new DnsEndPoint(Hostname, Port);
_logger.LogInformation($"Attempting connection to {dest.Host}:{dest.Port}");
_logger.LogInformation($"Socket blocking: {client.Blocking}");
_logger.LogInformation("Calling BeginConnect");
var thd = client.BeginConnect(dest, new AsyncCallback(ConnectCallback), client);
_logger.LogInformation("BeginConnect complete");
_logger.LogInformation("Calling WaitOne");
finish.WaitOne(); // don't let program end until connection is made
_logger.LogInformation("WaitOne complete");
client.Close();
Thread.Sleep(25); // if you don't do this the program ends before all the log output can be written
Console.WriteLine("Program complete");
}
}
}
我已經使用.NET Core 2.1測試了此代碼,並且您需要以下nuget包來運行它:
Microsoft.Extensions.Logging Microsoft.Extensions.Logging.Console Microsoft.Extensions.Logging.Debug"
成功執行如下所示:
info: socketTst.Program[0] Attempting connection to www.google.com:80 info: socketTst.Program[0] Socket blocking: True info: socketTst.Program[0] Calling BeginConnect info: socketTst.Program[0] BeginConnect complete info: socketTst.Program[0] Calling WaitOne info: socketTst.Program[0] ## ConnectCallback entered info: socketTst.Program[0] ## Connection to server successful at 172.217.15.68:80 info: socketTst.Program[0] ## Data returned: HTTP/1.0 400 Bad Request Content-Length: 54 Content-Type: text/html; charset=UTF-8 Date: Wed, 26 Sep 2018 03:32:39 GMT <html><title>Error 400 (Bad Request)!!1</title></html> Program complete
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.