【问题标题】:NullReferenceException in TCPClient when connecting to the server in a loop循环连接到服务器时 TCPClient 中的 NullReferenceException
【发布时间】:2013-12-13 13:45:51
【问题描述】:

我正在 c# 中的 .net 下通过我的测试客户端测试一些基于 tcp ip 的服务器。

我的测试客户端类是一些琐碎的异步套接字代码:

public void Connect()
    {
        try
        {
            _tcpClient.BeginConnect(IPAddress, Port, OnConnectCallBack, null);
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
        }
    }

private void OnConnectCallBack(IAsyncResult ar)
    {
        try
        {
            _tcpClient.EndConnect(ar);

        }
        catch (Exception exc)
        {
            Debug.WriteLine("Connection error: " + exc.Message);
        }
    }

_tcpClient 是一个 TcpClient 实例。

我尝试一次与服务器建立数个 (100) 连接以对其进行压力测试。如果我在调用 connect 之间添加一些 50 毫秒的睡眠,它就像一个魅力。但是,当我尝试在 foreach(...) 迭代中连接而不在连接之间添加睡眠时,OnConnectCallBack 引发异常:System.dll 中发生了“System.NullReferenceException”类型的第一次机会异常。连接错误:对象引用未设置为对象的实例。 有时我得到目标机器拒绝连接异常。

设置断点后发现来自_tcpClient:看不到它的方法和属性值,都是空引用异常值,其Client属性为空。

在 TestClient.OnConnectCallBack(IAsyncResult ar) C:...\TestClient.cs(82) 在 LazyAsyncResult.Complete(IntPtr userToken)
在 ContextAwareResult.CompleteCallback(对象状态)
在 ExecutionContext.runTryCode(Object userData)
在 RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode 代码、CleanupCode backoutCode、对象 userData)
在 ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback 回调, 对象状态)
在 ExecutionContext.Run(ExecutionContext executionContext, ContextCallback 回调, 对象状态, Boolean ignoreSyncCtx)
在 ExecutionContext.Run(ExecutionContext executionContext, ContextCallback 回调, 对象状态)
在 ContextAwareResult.Complete(IntPtr userToken)
在 LazyAsyncResult.ProtectedInvokeCallback(对象结果,IntPtr userToken)
在 LazyAsyncResult.InvokeCallback(对象结果)
在 QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
在 ThreadPoolWorkQueue.Dispatch()
在 _ThreadPoolWaitCallback.PerformWaitCallback()

【问题讨论】:

  • 如果没有延迟,是不是TcpClientBusyConnect()忙,阻止了重入?目标机器错误可能是服务器没有足够的队列槽在listen()中等待的结果。
  • 嗨佩卡!谢谢! 'BusyConnect()' 是什么意思?
  • 对不起。我的意思是BeginConnect()。由于操作是异步的,因此在所有情况下调用该方法都是不安全的。您没有解释您是否正在尝试对服务器进行功能检查的压力测试。如果是第一个,您可以为每个连接使用 TcpClient 的单独实例。
  • 原因是:做压力测试,没错。我为每个连接使用单独的 TcpClients,这就是为什么它如此奇怪......
  • 请发布堆栈跟踪。我怀疑不知何故您没有使用多个 TcpClient 实例。 .NET 框架几乎没有错误,尤其是在经过十年的生产强化之后。很难相信你找到了一个简单的程序。

标签: c# .net sockets nullreferenceexception


【解决方案1】:

在我看来,此行为是在同一 TcpClient 实例上多次调用异步方法 BeginnConnect 的结果,而无需等待已建立的连接。

根据压力测试的意图,您有(至少)两种可能性:

  1. 如果你想用多个TcpClients 来强调你的应用程序,你可以创建一个TcpClients 的列表并遍历这个列表来调用BeginConnect。您应该在参数中传递TcpClient 的实例,以便在回调函数中拥有此实例。

  2. 要通过快速连接(但一次只能连接一个)给您的应用程序带来压力,请致电 Connect 而不是 BeginnConnect。这将阻塞线程,直到建立连接。之后您直接拨打Close 断开连接。由于这会处理 TcpClient,因此您必须在再次调用 Connect 之前创建一个新实例。

【讨论】:

    【解决方案2】:

    如果没有看到有关如何使用此方法的代码(提示:发布您的代码),很难确定问题所在。

    根据您的解释,我猜您正在尝试在多个并发操作中使用 TcpClientTcpClient 不支持并发操作;您可以使用BeginXXXEndXXX 对来异步执行操作,但异步处理不等于并发处理。

    为每个并发操作创建一个TcpClient 的实例来解决您的问题。这可以通过在每次循环运行时创建一个来轻松实现。

    【讨论】:

      猜你喜欢
      • 2014-08-05
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 2014-08-19
      相关资源
      最近更新 更多