请教异步BeginAcceptTcpClient后,系统会自动创建新线程嘛?

问题描述

在网上搜索到的资料上说引用

程序执行BeginAcceptTcpClient方法后,即在线程池中自动创建需要的线程,同时在自动创建的线程中监听客户端连接请求。

不知道是不是这样。请教大神其中的细节,或者出处。谢谢!

解决方案

解决方案二:
这肯定是有误导成分的。系统级的东西是事件驱动的,哪里跟初学者一样去搞什么线程进行“死循环、阻塞、额外监听”呢。这个方法注册了回调。当系统收到消息后,才会创建(或者说使用)I/O子线程回调。
解决方案三:
谢谢。现在的程序如下//这是一个新线程privatevoidAcceptConnect(){//获取本机所有IP地址DDIPAddress[]ip=Dns.GetHostAddresses(Dns.GetHostName());listener=newTcpListener(ip[0],51888);//开始侦听客户端listener.Start();//然后新线程始终在这里循环while(isExit==false){try{//等.WaitOne()来阻塞线程。allDone.Reset();//引用在异步操作完成时调用的回调方法AsyncCallbackcallback=newAsyncCallback(AcceptTcpClientCallback);listBoxStatus.Invoke(setListBoxCallback,"开始等待客户连接");//开始一个异步操作接受传入的连接尝试listener.BeginAcceptTcpClient(callback,listener);//阻塞当前线程,直到收到客户连接信号allDone.WaitOne();}catch(Exceptionerr){listBoxStatus.Invoke(setListBoxCallback,err.Message);break;}}//}

然后系统在接收到一个客户端连接后,自动调用回调函数如下privatevoidAcceptTcpClientCallback(IAsyncResultar){try{//允许线程需要进行allDone.Set();TcpListenermyListener=ar.AsyncStateasTcpListener;TcpClientclient=myListener.EndAcceptTcpClient(ar);//偿试以非同步方式接入连接,并建立新的TcpClient处理与远程主机通讯//UI刷新listBoxStatus.Invoke(setListBoxCallback,"已接受客户连接:"+client.Client.RemoteEndPoint);comboBox1.Invoke(setComboBoxCallback,client.Client.RemoteEndPoint.ToString());//读取数据ReadWriteObjectreadWriteObject=newReadWriteObject(client);clientList.Add(readWriteObject);SendString(readWriteObject,"服务器已经接受连接,请通话");readWriteObject.netStream.BeginRead(readWriteObject.readBytes,0,readWriteObject.readBytes.Length,ReadCallback,readWriteObject);//每接收一个客户端,加1number_thread=number_thread+1;textBox1.Invoke(setLableThreadCallback,number_thread.ToString());//在UI线程上显示}catch(Exceptionerr){listBoxStatus.Invoke(setListBoxCallback,err.Message);return;}}

这里readWriteObject发送、接收信息,与客户端进行通讯。这样连续接入10个客户端,并且每个客户端进行通讯。请问,此时这10个客户端是共用一个线程,还是系统给它们各自开辟线程进行“发送、接收”操作的呢?
解决方案四:
另外,如果这样的程序结构,当客户端多达100个时,通讯会不会变慢、变卡?我理解是如果是“系统给它们各自开辟线程进行“发送、接收”操作”,那就不会变卡。我测试过在本机上开辟20个客户端与之通讯(传送1页A4纸字符),很通畅。
解决方案五:
对于readWriteObject.netStream.BeginRead的工作方式,我理解不透它。因为从程序代码上后,每次每个客户端接入时,只调用过它一次,并没有第二次、第三次调用它。而每个客户端与服务端连接上后,就可以任意次通讯了。为什么?
解决方案六:
我从来不在AcceptConnect中写while语句、WaitOne语句。写了它们,显然你的程序的变得复杂了。你的代码,使得父线程被阻塞,然后等回调时父线程才继续执行(继续while循环),这完全是画蛇添足的写法,与其这样纠结还不如直接写成同步Accept。实际上,AcceptConnect在注册完异步回调之后可以直接结束。然后等回调时在调用一次AcceptConnect。至于说你问“这10个客户端是共用一个线程,还是系统给它们各自开辟线程进行“发送、接收”操作的”,这也类似,这根本就是被误导出来的问题。10各连接所调用的AcceptTcpClientCallback过程,可能是在一个线程、也可能用了5个线程,也可能用了10个线程,完全看系统线程池怎么调配。但是有一点的明确的,就是调用时肯定是互不相干的,比如说第一个线程还没有放回系统线程池的时候肯定不会被线程池用于处理第二个异步Accept回调。而在AcceptTcpClientCallback方法中,也不过是向NetworkStream注册了异步Read方法,然后它就结束了。它既没有while循环,也没有阻塞。迅速结束AcceptTcpClientCallback方法,就能让此I/O线程立刻回归线程池。等系统接收到消息到来,又是系统从线程池中分配出I/O线程来调用之前注册的ReadCallback委托。此时至于说是跟其它处理用了同一个线程,还是不是同一个线程,或者同一个用户的不同处理用了同一个线程还是1000个不同的线程,这都是线程池调度的事情。反正只要前一个线程的方法没有结束,系统线程池就不得不另外分配其它线程。而你的ReadCallback委托处理中同样也是这样,如果你是异步处理消息的,从而立刻结束ReadCallback委托方法,那么就能让迅速地释放I/O线程给系统池,从而提高通讯程序并发。总之,只有事件发生时才会占用线程。可不是纠结那么11个线程先在那里死循环着!你的AcceptConnect中不应该写“循环、阻塞”的语句。你在异步Read的程序中写的是对的,没有搞什么循环、阻塞。过程代码立刻结束,把I/O线程立即释放(回线程池),这是很重要的事情。绝不能占着I/O线程在那里做一堆Worker线程的事情,更不应该“循环、阻塞”线程。
解决方案七:
引用4楼abc2363789187的回复:

对于readWriteObject.netStream.BeginRead的工作方式,我理解不透它。因为从程序代码上后,每次每个客户端接入时,只调用过它一次,并没有第二次、第三次调用它。而每个客户端与服务端连接上后,就可以任意次通讯了。为什么?

看不到你的readCallback中的代码,不知道程序设计的逻辑是什么。如果你看不到继续调用它,那么可能是这个程序的设计者:1.是在写一个“短链接”通讯程序,因此只要“读”数据然后“写”数据,之后就把连接关闭了。2.他没有考虑一次Read可能不能读取完整的消息的问题,他以为一定可以再一次Read时得到客户端发来的所有数据。这第一点,是可以理解的。而第二点,可能是个bug,当网路不是很好的时候就会出现读取数据不足、而需要多次Read的问题。
解决方案八:
引用3楼abc2363789187的回复:

另外,如果这样的程序结构,当客户端多达100个时,通讯会不会变慢、变卡?我理解是如果是“系统给它们各自开辟线程进行“发送、接收”操作”,那就不会变卡。我测试过在本机上开辟20个客户端与之通讯(传送1页A4纸字符),很通畅。

异步处理方式,即使你的服务端使用(仅仅)一个端口连接10万个在线客户端,可能占用线程也就是10几个。而使用线程少,基本上就说明你的程序设计得不纠缠CPU了。

时间: 2024-09-20 11:40:12

请教异步BeginAcceptTcpClient后,系统会自动创建新线程嘛?的相关文章

Win7系统中怎么创建新的磁盘分区

  win7有库的设置,很贴心.但它默认的位置是C盘,很占空间.如果可以新建一个磁盘分区,那就可以更方便的使用电脑.本文,小编就来为你解决这个问题"Win7怎么创建新的磁盘分区",具体请看下面的"新建磁盘分区图文教程". 具体方法: 第一步.鼠标右键点击桌面上"计算机",选中"管理",即可打开"计算机管理"窗口. 第二步.在"计算机管理"窗口的左侧,我们点击"磁盘管理"

linux下怎么写一个自动创建文件夹和文件的脚本?

问题描述 linux下怎么写一个自动创建文件夹和文件的脚本? linux下怎么写一个自动创建文件夹和文件的脚本?就是说我给一个绝对路径,程序会自动帮我创建在路径中没有的文件夹和文件. 解决方案 http://blog.csdn.net/hellochenlian/article/details/37566269 -p, --parents 可以是一个路径名称.此时若路径中的某些目录尚不存在,加上此选项后,系统将自动建立好那些尚不存在的目录,即一次可以建立多个目录; 解决方案二: mkdir 加上

怎么给电脑创建新的管理员用户呢?

(1)在电脑中我们右击"我的电脑"  (2)然后点击"管理", (3)这时就进入计算机的"本地用户和组" 我们点击左边的. (4)我们再右击右边空白片 (5)在弹出菜单"新用户"如图所示. (6)我们输入用户名与密码"用户不能更改密码"和"密码永不过期".点击"创建",系统会自动创建一个新的用户. (7)现在在用户管理中右边就会看到有你刚创建的号了. (8)现在来设置

Win7系统笔记本唤醒休眠模式后无线无法自动连接怎么办

  Win7系统笔记本唤醒休眠模式后无线无法自动连接怎么办           故障原因: 出现这样的情况多半是在笔记本win7系统进入休眠或睡眠关闭了无线适配器的,这是由于电源选项设置为节能模式模式引起的,则无线网络连接可能不会重新连接. 解决步骤: 1.首先从开始菜单打开"控制面板"; 2.在控制面板中进入"系统和安全"; 3.在当前所选的电源计划旁边,单击"更改计划设置"; 4.进入后再点击"更改高级电源设置"选项; 5

Win8系统如何关闭自动创建图片缓存缩略图功能?

  Win8系统如何关闭自动创建图片缓存缩略图功能? 1.首先,请大家按下Windows徽标键+R键,打开运行命令框,然后输入"gpedit.msc"命令,打开组策略编辑器; 2.进入Windows组策略编辑器以后,依次双击左侧栏目的"用户配置--管理模板"选项; 3.进入Windows管理模板以后,查看子目录下的"Windows组件"文件夹,同时在该文件夹下找到"文件资源管理器"; 4.在文件资源管理器子目录选项下,找到&q

请教如何使用js和css使使用了位置为absolute的div删除后,后面的div自动填充到删除的位置

问题描述 请教如何使用js和css使使用了位置为absolute的div删除后,后面的div自动填充到删除的位置.具体如下:页面有两行图标,每个图标都是位置为absolute的div,用户删除掉中间的一个图标后,后边的图标自动前移,页面用js+div+css开发环境是vs2008 解决方案 解决方案二:不想用absulute,全部用float解决方案三:对啊用float解决方案四:用floatcss中最好不要用绝对定位,用浮动就好了解决方案五:用absulute,会限制死位置解决方案六:abso

APP注册完成后会自动创建环信账号如何实现

问题描述 本人是IOS菜鸟,需要做的是APP注册完成后会自动创建环信账号,该帐号唯一且不需用户关心,登录环信时用户名和密码都使用该账号即可,这个如何实现有谁做过的请给我个具体的步骤,谢谢 解决方案 你可以调用rest接口注册im用户 http://docs.easemob.com/doku.p ... %23im用户管理

U盘装WIN7安装程序无法定位现有分区,也无法创建新的系统分区(转载)

  我最近装WIN7,格了盘之后,总是出现提示"安装程序无法定位现有分区,也无法创建新的系统分区",想了很多办法,总是无法解决,后来经过多方查找,于昨天晚上终于把系统装上了.     我用U盘装系统,是因为我的光驱读盘不好,有时读不出来,有时又能读出来,所以才想到用U盘来装系统.当然了,你的电脑得支持U盘启动才行,下面开始说处理过程,网上能搜到很多的.现在我把我的处理过程总结如下:     1.首先,准备一个3G以上的U盘,因为WIN7的系统安装包有2.8G,U盘制作成PE启动盘后,会

c语言-C语言怎样编写程序运行完后,不自动结束,而是返回程序的开始的主菜单?

问题描述 C语言怎样编写程序运行完后,不自动结束,而是返回程序的开始的主菜单? 我的程序运行完一个功能后按任意键就退出了,而不是返回主菜单 代码如下,应该怎么改?(具体一点,菜鸟一个)多谢! #include #include #include #include #include #define LENTEL sizeof(tel) #define ID struct tel struct tel { char name[15]; char tele[11]; char style[15]; c