草庐IT

c# - TcpListener/TcpClient 在某些情况下停止处理数据

coder 2023-09-19 原文

我有一个问题,根据两个网络设备的启动顺序,我似乎失去了在一端接收数据的能力。

设置是一个用 C# (.NET 4.0) 编写的小型服务器,它监听来自工业扫描仪的数据的特定端口,通过 TCP 进行通信。扫描器可以很好地连接到服务器应用程序,并将发送服务器接收和处理的小数据 block (序列号)。但是,在扫描仪上重新启动(实际上,循环电源,并不能优雅地关闭其连接)会导致服务器停止处理数据。事件的顺序以及导致问题的关键网络流量如下:

             SUCCESS                           FAILURE
     |----------------------|             |----------------------|
     |  SCANNER  |  SERVER  |             |  SCANNER  |  SERVER  |
     |----------------------|             |----------------------|
     |           |   Starts |             |  Starts   |          |
     |   Starts  |          |             |           |  Starts  |
     |    Scan   | Received |             |   Scan    | Received |
     |  Restarts |          |             |  Restarts |          |
     --------(Network)-------             --------(Network)-------
     |    SYN    |          |             |    SYN    |          |
     |           | ACK-123  |             |           | SYN ACK  |
     | RST - 123 |          |             |    ACK    |          |
     |    SYN    |          |             |           |          |
     |           |  SYN ACK |             |           |          |
     |    ACK    |          |             |           |          |
     |----------------------|             |----------------------|  
     |    Scan   | Received |             |    Scan   |  !LOST!  |
     |----------------------|             |----------------------|      

如您所见,在 SUCCESS 场景中,扫描器重新启动后,服务器使用 ACK 响应 SYN,并且扫描器重置连接,因为它意识到它不在正确的流中。服务器检测到这一点并优雅地处理它。然而,在 FAILURE 场景中,服务器很高兴地用 SYN ACK 响应,扫描器 ACK,并建立了新的连接。

代码没有提示任何事情,但是我的 TcpLister/TcpClient 似乎再也没有接收到任何数据,即使在 Wireshark 中看到它被接收和确认时也是如此。似乎 TcpListener 和处理程序仍在等待旧连接以获取数据?我是这个级别的网络编程的新手(对于 C# 本身也是相对较新的),所以如果我遗漏了一些明显的东西,一定要指出。

服务器代码片段:

public void Run() 
 {
   while (!shutdown)
   {
     shutdown = false; // Reset
     listenerServer = new TcpListener(IPAddress.Any, scanner.Address.Port);

     try
     {
       listenerServer.Start();
       TcpClient handler = listenerServer.AcceptTcpClient();

       while (true)
       {
         try
         {
           incomingData = null;
           dataBuffer = new Byte[256];
           NetworkStream stream = handler.GetStream(); // blocks here
           int i;

           while ((i = stream.Read(dataBuffer, 0, dataBuffer.Length)) != 0)
           {
             incomingData += Encoding.ASCII.GetString(dataBuffer, 0, i);
             int startIndex = incomingData.IndexOf(startMarker);
             int endIndex = incomingData.IndexOf(endMarker);
             if (startIndex > -1 && endIndex > -1)
             {
               string serialData = incomingData.Substring(startIndex + 1, endIndex - startIndex - 1);
               scanner.ProcessDataChange(serialData);
             }
           }
         }
         catch (IOException e)
         {
           // Deals with SocketExceptions here...
         }
         finally
         {
           handler.Close();
         }
       }
     }
     catch (SocketException e)
     {
       listenerServer.Stop();
       listenerServer = null;
     }
     finally
     {
       listenerServer.Stop();
       listenerServer = null;
     }
   }
 }

最佳答案

用户 @LB (L. B)回答了一个问题,但认为它可能无关紧要而将其删除。事实上,这是对这个问题的一个很好的回答,所以我在这里重新发布它。最后,我没有听取正在建立的新联系。 如果 L. B 希望重新发布他的答案,我会很乐意接受。

转载L.B的回答

你只接受一个与 TcpClient 的连接 handler = listenerServer.AcceptTcpClient();

当第一个连接关闭时,您不再接受连接。您应该将它移到 while 循环中。

编辑

这不是对您问题的直接回答。但是我尝试了下面的代码并且效果很好。如果你愿意,你可以试试。我稍后会删除此答案。

 void Run()
 {
     TcpListener listener = new TcpListener(IPAddress.Any, 12345);
     listener.Start();

    Task.Factory.StartNew(() =>
    {
        while (true)
        {
            var client = listener.AcceptTcpClient();
            Task.Factory.StartNew(() => Handler(client), TaskCreationOptions.LongRunning);
        }
    }, TaskCreationOptions.LongRunning);
 }

 void Handler(TcpClient client)
 {
     using (NetworkStream stream = client.GetStream())
     {
         var dataBuffer = new Byte[256];
         int i;
         while ((i = stream.Read(dataBuffer, 0, dataBuffer.Length)) != 0)
         {
             // Processes data here..
             //var s = Encoding.UTF8.GetString(dataBuffer, 0, i);
             //Console.Write(s);

         }
     }
 }

关于c# - TcpListener/TcpClient 在某些情况下停止处理数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13404803/

有关c# - TcpListener/TcpClient 在某些情况下停止处理数据的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  6. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. ruby - 在不使用 RVM 的情况下在 Mac 上卸载和升级 Ruby - 2

    我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案

  10. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

随机推荐