如果没有有效的示例,就很难知道。如果这与您实际在做的事情接近,我怀疑有几件事是错误的。默认情况下, Socket 对象似乎是阻塞的,但有些东西正在生成您的异常,它可能不是您认为的那样。首先要做的是只捕获 SocketException,然后仅在异常表示可能表明重试可行的情况时重试。延迟,因为如果它在 1 毫秒前不起作用,它现在可能不会起作用。放入一个理智计数器,以便在多次尝试后放弃重试。检查您的协议以确保您正在向服务器发送它所期望的内容。最重要的是关闭你的套接字。
我怀疑您看到的是由异常引起的一堆 Socket 连接(可能与套接字相关,也可能不相关)。由于您从不关闭它们,因此它们只会累积。我怀疑最终 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"
成功执行如下:
信息:socketTst.Program[0]
尝试连接到 www.google.com:80
信息:socketTst.Program[0]
套接字阻塞:真
信息:socketTst.Program[0]
呼叫 BeginConnect
信息:socketTst.Program[0]
开始连接完成
信息:socketTst.Program[0]
呼叫 WaitOne
信息:socketTst.Program[0]
## ConnectCallback 输入
信息:socketTst.Program[0]
## 在 172.217.15.68:80 连接到服务器成功
信息:socketTst.Program[0]
## 返回的数据:HTTP/1.0 400 错误请求
内容长度:54
内容类型:文本/html;字符集=UTF-8
日期:格林威治标准时间 2018 年 9 月 26 日星期三 03:32:39
错误 400(错误请求)!!1
程序完成