C# TcpClient.EndConnect在套接字关闭时引发NullReferenceException
我正在尝试使用C# TcpClient.EndConnect在套接字关闭时引发NullReferenceException,c#,sockets,asynchronous,connection,tcpclient,C#,Sockets,Asynchronous,Connection,Tcpclient,我正在尝试使用TcpClient.BeginConnect/TcpClient.EndConnect组合连接到我的服务器。然而,有些事情并没有像它们应该的那样起作用 情况如下: 调用TcpClient.BeginConnect 服务器故意脱机(出于测试目的)-因此无法建立连接 我关闭应用程序(client.close()在以下过程中被调用) TcpClientconnection回调方法在给出IAsyncResult 使用给定的IAsyncResult NullReferenceExcepti
TcpClient.BeginConnect/TcpClient.EndConnect
组合连接到我的服务器。然而,有些事情并没有像它们应该的那样起作用
情况如下:
- 调用
TcpClient.BeginConnect
- 服务器故意脱机(出于测试目的)-因此无法建立连接
- 我关闭应用程序(
在以下过程中被调用)client.close()
connection回调方法在给出TcpClient
IAsyncResult
- 使用给定的
IAsyncResult
发生在NullReferenceException
(?)EndConnect
- 由于上一个窗体(窗口)已关闭,应用程序应该退出-但是它不会退出,至少在
操作完成之前不会退出(这很奇怪,因为已经调用了回调)BeginConnect
NullReferenceException
。如上图所示,client
和ar
都不是null
。问题在于,没有提到引发此异常的情况
所以基本上,我不知道发生了什么。问题是我被迫等待应用程序关闭(好像连接操作仍在等待超时)。如果服务器处于联机状态,则可以正常连接和断开连接
在本上下文中NullReferenceException
是什么意思?如果无法建立连接,如何避免BeginConnect
操作阻止应用程序关闭
附加说明(在评论中要求): 以下是创建客户机的代码(客户机是一个成员变量:
public void Connect()
{
try
{
lock (connectionAccess)
{
if (State.IsConnectable())
{
// Create a client
client = new TcpClient();
client.LingerState = new LingerOption(false, 0);
client.NoDelay = true;
State = CommunicationState.Connecting;
client.BeginConnect(address, port, onTcpClientConnectionEstablished, null);
}
else
{
// Ignore connecting request if a connection is in a state that is not connectable
}
}
}
catch
{
Close(true);
}
}
此外,关闭方法:
public void Close(bool causedByError)
{
lock (connectionAccess)
{
// Close the stream
if (clientStream != null)
clientStream.Close();
// Close the gateway
if (client != null)
client.Close();
// Empty the mailboxes
incomingMailbox.Clear();
outgoingMailbox.Clear();
State = causedByError ? CommunicationState.CommunicationError : CommunicationState.Disconnected;
}
}
我遇到了一个类似的错误,并最终使用了此代码。我不确定IASyncResult接口是否支持此错误,但可能有类似的方法来运行此检查。我确实注意到您的ar.AsyncState==null,因此可能尝试从那里开始,即当您正确连接时是否为null
private void connConnectCompleted(AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
// Something didn't work...abort captain
CloseSocket();
Console.WriteLine(this.GetType().ToString() + @":Error connecting socket:" + e.Error.Message);
return;
}
// Do stuff with your connection
}
编辑:很抱歉,我没有意识到我没有发布生成AsyncCompletedEventArgs的内容,这与您正在做的事情更相关。您将看到我为什么怀疑ar.AsyncState为null的原因
private void OnConnect(IAsyncResult asyncResult)
{
if (OnConnectCompleted == null) return; // Check whether something is using this wrapper
AsyncCompletedEventArgs args;
try
{
Socket outSocket = (Socket) asyncResult.AsyncState;
// Complete connection
outSocket.EndConnect(asyncResult);
args = new AsyncCompletedEventArgs(null);
OnConnectCompleted(this, args);
}
catch (Exception e)
{
args = new AsyncCompletedEventArgs(e.Message);
OnConnectCompleted(this, args);
}
}
NullReferenceException
可能是由于TcpClient.Client
为空
private void OnConnect(IAsyncResult asyncResult)
{
if (OnConnectCompleted == null) return; // Check whether something is using this wrapper
AsyncCompletedEventArgs args;
try
{
Socket outSocket = (Socket) asyncResult.AsyncState;
// Complete connection
outSocket.EndConnect(asyncResult);
args = new AsyncCompletedEventArgs(null);
OnConnectCompleted(this, args);
}
catch (Exception e)
{
args = new AsyncCompletedEventArgs(e.Message);
OnConnectCompleted(this, args);
}
}
如果要遵循forTcpClient.BeginConnect
并将TcpClient
对象作为状态对象传递:
private void onConnEst(IAsyncResult ar)
{
try
{
TcpClient client = (TcpClient)ar.AsyncState;
if(client!=null && client.Client!=null)
{
client.EndConnect(ar);
}
}
catch(Exception ex){...}
}
这应该可以处理在回调之前调用Close()
的情况
回到您的问题—应用程序最终关闭需要多长时间?这显然是TcpClient类中的一个错误。我也遇到过它。TcpClient.Dispose可能会将客户端字段设置为null,但EndConnect不希望如此。这是一个错误
您应该收到的是“ObjectDisposedException”,而不是“NullReferenceException”。InnerException是否提供了有关NULL内容的更多信息?@Tremmors Nope.InnerException为NULL。StackTrace也没有提供帮助(onTcpClientConnectionEstablished>EndConnect):(是的,显然是一个框架错误。如果TcpClient在EndConnect()之前关闭)调用时,它应该抛出ObjectDisposedException。我似乎得到了NullReferenceException,而不是前一两次,然后它将按照预期开始抛出ObjectDisposedException。我建议您只需像处理ObjectDisposedException一样处理它(即。“连接超时/失败/无论您调用Close()”的其他原因是什么。但是,我不知道是否有任何资源可能在这里泄漏,因为EndConnect()未完成。GC可能无法处理任何内容。:)在.NET 4.8中,这一问题是如何解决的?AsyncState用于将一些自定义数据传递给回调方法。我没有这种需要,因此它为null。它不会产生错误。我不理解您的示例(它不完整)。IAsyncResult没有错误,我想您应该提供CloseSocket()的代码方法,因为它是您自己的自定义方法。Othwerise,我不知道您的代码示例会有什么帮助。CloseSocket()只是触发几个事件来通知程序的任何其他部分,然后运行。Close()在套接字上。为什么强制转换ar.AsyncResult?您是指ar.AsyncState吗?无论如何,我的客户端是一个私有成员,因此我不需要将其传递给async方法。我当前无法(即不在工作中)检查TcpClient.Client是否为null。但是,根据我的内存和以前的经验,如果我不调用Client.EndConnect,当我尝试关闭它时,应用程序仍然挂起。它通常与连接超时(约20秒)的持续时间相同。如果我在连接尝试期间不关闭应用程序,BeginConnect将在同一时间失败。Oops-您是对的,
ar.AsycResult
应该是ar.AsyncState
。进行后期编辑以反映更改。您是否能够发布如何构建TcpClient和BeginConnect?是否在创建之前绑定套接字eginConnect?另外,这并不重要,但你使用的是什么.Net框架?我已经更新了问题以填补缺失的部分。我使用的是.Net 4。虽然我没有准确运行你的代码,但Client.Close()不会花太长时间。我建议注释掉你代码中的TcpClient部分(仅用于测试目的)看看你是否仍然体验到了延迟。除此之外,可能有一些多线程被锁定在<代码>连接访问>代码>中,这会导致延迟,如果你在代码中没有经历延迟,这将是有意义的。欢迎这么做!你可能要考虑精心设计。