如果客户端无法连接到服务器,我正在尝试重试编码。以下是我的方法:
在主要功能中:
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个连接。
我的编码有误吗?好像每次重试,我的服务器都会获得一个新的连接。
答案 0 :(得分:0)
没有有效的示例,很难知道。如果这与您的实际操作很接近,我怀疑有几件事是错误的。默认情况下,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