胶衣漫画:与Socket的“再次见面”

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 23:20:42

与Socket的“再次见面”

注:

    这是一个针对 网络开发领域初学者 的系列文章,可作为《.NET 4.0 面向对象编程漫谈 》一书的扩充阅读,写作过程中我假设读者可以对照阅读此书的相关章节,不再浪费笔墨重复介绍相关的内容。

    对于其他类型的读者,除非您已经有相应的.NET 技术背景与一定的开发经验,否则,阅读中可能会遇到困难。

    我希望这系列文章能让读者领略到网络开发的魅力!

    另外,这些文章均为本人原创,请读者尊重作者的劳动,我允许大家出于知识共享的目的自由转载这些文章及相关示例,但未经本人许可,请不要用于商业盈利目的。

      本文如有错误,敬请回贴指正。

    谢谢大家!

 

                                                          金旭亮

=================================================

点击以下链接阅读本系列前面的文章:

 

《 开篇语—— 无网不胜》

《 IP知多少》

《我在“网” 中央 》

《与Socket的第一次“约会” 》

=================================================

    前一篇文章介绍了与Socket的第一次“约会”经历,看来双方的第一印象不错,不然读者也不会做出一个“继续交往”的决定,并继续阅读本篇文章了。 :)
    在这篇文章中,计划介绍两方面的内容:
    Socket的连接请求队列和如何开发“一问一答”的网络应用程序。


    1 Socket的“连接请求队列” 

    在现实生活中,一名品貌俱佳的女孩总是不乏追求者,人们会打趣地说“她的追求者有一个班”,这样的一个女孩,在同一时间段内收到多个约会请求实在是太常见的事,当然,到底接受谁的约会邀请,就要看她中意谁了。
    类似地,当一个绑定到特定终结点的Socket对象开始“监听(Listen)”时,完全有可能有多个客户端向此Socket同时发出多个连接请求,Socket对象必须决定如何处理这些连接请求。
    为了方便处理,操作系统也会给每个正在监听的Socket分配一个“连接请求队列”,将收到的客户端连接请求追加到此队列中:


 
图 1



    由于网络服务器上可能同时会有多个Socket同时监听,我们应该给每个Socket对象分配一个 “适当容量”的队列,以避免过多地占用系统资源,让网络服务器能服务更多的在线用户。


    请求队列的容量由Socket.Listen方法的参数backlog确定:

    public void Listen(int backlog );

    例如,以下代码指定newSocket对象最多只能接收10个连接请求:

    newsock.Listen(10 );

    更详细地说,如果newSocket对象正在忙于处理某个连接请求时,操作系统又接收到了多个尝试连接此newSocket对象的请求,操作系统会把这些请求追加到newSocket对象所关联的请求队列中。
    newSocket对象处理完当前连接之后,它再从关联的请求队列中取出一个处理。


    一个有趣的问题是:如果某一时间段内连接请求很多,请求队列“放不下”怎么办? 
    请看示例解决方案ConnectionQueueDemo。这个解决方案中的MyServerApp项目与前一讲 中的完全一样,也是接收并显示客户端发来的一句“问好”消息之后就断开与此客户端的连接。
    为了直观地体现连接请求队列的特性,MyServerApp项目有意识地指定一个容量为“1”的请求队列:

    newsock.Listen(1);

    在客户端项目MyClientApp2中,创建10个线程,每个线程都创建一个Socket对象并尝试着连接MyServerApp程序(图 2)。

     
 
图 2

    我们看到了非常著名的“目标计算机积极拒绝……”的信息,它是由以下这句英文直译过来的:



 …… the target machine actively refused it ……



    就汉语来说,这明显是一个病句,什么叫“积极拒绝”?难道还有“消极拒绝”?
    由此可见负责汉化Windows的程序员要不是“语文”学得不太好,要不就是“过于死板”了,个人觉得,此处意译为以下这句更好:
    尝试连接的计算机拒绝了连接请求。 
    从示例中我们可以得到结论:
    当尝试连接的客户端发来的连接请求数目过大,超过了服务端Socket的连接请求队列容量时,未能进入队列的请求将会被丢弃,而客户端将会得到一个代码为10061的SocketException。    客户端可以捕获此异常,等待一定的时间再尝试连接。


    2 开发“一问一答”的网络应用程序


    在各种网络应用程序中,“一问一答”可以说是最常见的一种类型。基于Socket实现这种类型的网络应用程序是非常简单的:
    在服务端与客户端配套使用Send和Receive方法,只要传送的数据不超过缓冲区的大小限制,就可以实现“一问一答”的标准C/S架构程序。 
    请看示例解决方案EchoServiceDemo(图 3):

  
图 3



    EchoServiceDemo示例没什么复杂的,大家看看示例源码就清楚了。


    看懂源码后,请读者做做以下实验:


    (1)先运行服务端程序EchoServiceApp,然后,运行客户端程序EchoServiceClientApp连接上服务端,与EchoServiceApp进行交谈,注意不要输入“exit”命令退出。
    (2)再运行EchoServiceClientApp的另一个实例,尝试连接EchoServiceApp,发生了什么?
    (3)运行EchoServiceClientApp的第3个实例,尝试连接EchoServiceApp,又发生了什么?


    你能利用已经掌握的知识解释发生这些现象的原因吗?从这个实验中,您体会到了什么?总结出来了哪些经验?


    进一步地,读者现在能解决以下这个问题吗?


    你能想办法修改EchoServiceApp源码,让它同时可以服务多个客户端应用程序吗?

     提示: 
    (1)在EchoServiceApp程序中为每个客户端连接创建一个独立的线程,在此线程中完成“一问一答”的工作。
    (2)感到困难的读者请参看《.NET 4.0面向对象编程漫谈》,系统地学习第16章《多线程开发技术基础》。 

    此处只是介绍了开发“一问一答”的网络应用程序的最基础开发技巧,其实,这其中还有许多需要注意的“陷阱”,下一讲将介绍Socket编程中最大的“陷阱”--缓冲区问题,并开发第一个真正有点实用价值的网络应用程序--网络四则运算计算器。

========================================

点击下载示例源码


(在博客园:http://files.cnblogs.com/bitfan/AskAndAnswerSourceCode.rar )