简体   繁体   English

.NET中的异步TCP通信

[英]Asynchronous TCP Communication in .NET

Quick question here: is there any obvious benefit to use asynchronous communication with the NetworkStream class (generated by TcpClient), ie the BeginRead/BeginWrite methods rather than running a separate thread and using synchronous operations on that, ie Read/Write? 这里的快速问题:使用与NetworkStream类(由TcpClient生成)的异步通信有什么明显的好处,即BeginRead / BeginWrite方法,而不是运行单独的线程并对其使用同步操作,即读/写? My impression has been (it could easily be quite wrong) that the asynchronous operations are non-blocking and performed at OS-level (in the TCP stack perhaps?), with a thread pool item for the callback. 我的印象是(很可能是非常错误的)异步操作是非阻塞的并且在OS级别(在TCP堆栈中执行?)执行,并带有回调的线程池项。 I am thinking that it surely must be different from calling ThreadPool.QueueUserWorkItem on the synchronous method, or it there would be rather little point in providing it. 我认为它肯定必须与在同步方法上调用ThreadPool.QueueUserWorkItem不同,或者提供它时没有什么意义。 Now, I'm fairly confident this is the sort of thing (OS-level calls) that happens for file I/O at least, but if someone could please clarify the matter regarding network (TCP) communication, it would be most helpful. 现在,我相信这至少是文件I / O所发生的事情(操作系统级调用),但如果有人可以澄清有关网络(TCP)通信的问题,那将是最有帮助的。 Basically, I would like to know whether there's any specific benefit to either method (besides the obvious one of being able to use the BinaryReader/StreamReader classes with the synchronous calls). 基本上,我想知道这两种方法是否有任何特定的好处(除了能够在同步调用中使用BinaryReader / StreamReader类的明显优势)。

There is a difference, if you use a Worker thread to call the synchronous version you will tie up one of the threads on a blocking call. 不同之处在于,如果使用Worker线程调用同步版本,则会阻塞阻塞调用中的一个线程。

Whereas the Begin methods will not tie up a thread but will instead use a callback on an appropriate I/O signal, the call back will then run on a thread from the pool. 虽然Begin方法不会占用线程,但会在适当的I / O信号上使用回调,然后回调将在池中的线​​程上运行。

As others have pointed out, the allocation of another thread to your process will impact you when you use the synchronous method as you increase the number of simultaneous connections. 正如其他人所指出的那样,当您使用同步方法增加同时连接数时,将另一个线程分配给您的进程会对您产生影响。

However, if you know you will only ever have a small number of connections, I would say that it becomes a wash and you should choose the method that is most natural for your application. 但是,如果你知道你只会有少量连接,我会说它变成了一个清洗,你应该选择最适合你应用的方法。

In the case where the thread overhead is negligible, I would expect the two scenarios to play out like this. 在线程开销可以忽略不计的情况下,我希望这两个场景能够像这样发挥作用。

Asynchronous: 异步:

  1. You make call to BeginRead / BeginWrite 您调用BeginRead / BeginWrite
  2. "The system" (framework / OS) is informed of what you want “系统”(框架/ OS)被告知您想要什么
  3. Read / Write completes 读/写完成
  4. "The system" tells a thread in the thread pool to call your callback “系统”告诉线程池中的线程调用您的回调
  5. You do whatever you need to do to complete the operation 您可以做任何您需要做的事情来完成操作

Synchronous in another thread: 在另一个线程中同步:

  1. You get a thread from the thread pool to handle the IO 您从线程池中获取一个线程来处理IO
  2. You make call to Read / Write 你打电话给读/写
  3. "The system" (framework / OS) is informed of what you want “系统”(框架/ OS)被告知您想要什么
  4. Read / Write completes 读/写完成
  5. You do whatever you need to do to complete the operation 您可以做任何您需要做的事情来完成操作

The only difference here is that step 4 from the Asynchronous call becomes step 1 in the synchronous in another thread case. 这里唯一的区别是异步调用的第4步在另一个线程情况下成为同步中的第1步。

I agree with AnthonyWJones, imagine your thread pool has 10 threads, but you have 100 passive enought clients. 我同意AnthonyWJones,想象你的线程池有10个线程,但你有100个被动的enought客户端。 With async calls you can BeginRead for every one of them, and when data from some one is ready, it will be processed by one of the pool threads. 使用异步调用,您可以为每一个调用BeginRead,并且当某个数据准备就绪时,它将由其中一个池线程处理。 But if you will try to use QueueUserWorkItem, you'll schedule data receiving from only 10 clients. 但是,如果您尝试使用QueueUserWorkItem,则只会安排从10个客户端接收数据。 And if they send nothing in 1 hour, other 90 clients will never get a chance to get data. 如果他们在1小时内没有发送任何内容,其他90个客户将永远无法获得数据。

I'm not really sure why NetworkStream even has a BeginRead/Write, since this basically violates the purpose of the NetworkStream in the first place. 我不确定为什么NetworkStream甚至有一个BeginRead / Write,因为这基本上违反了NetworkStream的目的。 By using the Async methods, you gain faster response, greater scalability, and reduced resource consumption. 通过使用Async方法,您可以获得更快的响应,更高的可伸缩性和更少的资源消耗。

If you are only ever going to have one connection at a time, then it doesn't matter much if you use a thread pool thread or not, but if you accept many connections then you definitely want to use async. 如果你一次只有一个连接,那么如果你使用一个线程池线程没关系,但是如果你接受了很多连接,那么你肯定想要使用异步。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM