Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 操作系统 > 其他操作系统 > 用完成端口开发大响应规模的Winsock应用程序(5/完)
【标  题】:用完成端口开发大响应规模的Winsock应用程序(5/完)
【关键字】:Winsock,5/
【来  源】:http://www.cublog.cn/u/20391/showart.php?id=128375

用完成端口开发大响应规模的Winsock应用程序(5/完)

Your Ad Here
关键字 完成端口 Completion Port Scalability 

TransmitFile 和 TransmitPackets 

Winsock 提供两个专门为文件和内存数据传输进行了优化的函数。其中

TransmitFile()这个API函数在Windows NT 4.0 和 Windows 2000上都可以使用,

而TransmitPackets()则将在未来版本的Windows中实现。

TransmitFile()用来把文件内容通过Winsock进行传输。通常发送文件的做法是,

先调用CreateFile()打开一个文件,然后不断循环调用ReadFile() 和WSASend ()

直至数据发送完毕。但是这种方法很没有效率,因为每次调用ReadFile() 和 

WSASend ()都会涉及一次从用户模式到内核模式的转换。如果换成

TransmitFile(),那么只需要给它一个已打开文件的句柄和要发送的字节数,而

所涉及的模式转换操作将只在调用CreateFile()打开文件时发生一次,然后

TransmitFile()时再发生一次。这样效率就高多了。

TransmitPackets()比TransmitFile()更进一步,它允许用户只调用一次就可以发

送指定的多个文件和内存缓冲区。函数原型如下:
BOOL TransmitPackets(
SOCKET hSocket, 
LPTRANSMIT_PACKET_ELEMENT lpPacketArray,
DWORD nElementCount, 
DWORD nSendSize, 
LPOVERLAPPED lpOverlapped, 
DWORD dwFlags 
); 
其中,lpPacketArray是一个结构的数组,其中的每个元素既可以是一个文件句柄

或者内存缓冲区,该结构定义如下:
typedef struct _TRANSMIT_PACKETS_ELEMENT { 
DWORD dwElFlags; 
DWORD cLength; 
union {
struct {
LARGE_INTEGER nFileOffset;
HANDLE hFile;
};
PVOID pBuffer;
};
} TRANSMIT_FILE_BUFFERS;
其中各字段是自描述型的(self explanatory)。
dwElFlags字段:指定当前元素是一个文件句柄还是内存缓冲区(分别通过常量

TF_ELEMENT_FILE 和TF_ELEMENT_MEMORY指定);
cLength字段:指定将从数据源发送的字节数(如果是文件,这个字段值为0表示发

送整个文件);
结构中的无名联合体:包含文件句柄的内存缓冲区(以及可能的偏移量)。

使用这两个API的另一个好处,是可以通过指定TF_REUSE_SOCKET和TF_DISCONNECT

标志来重用套接字句柄。每当API完成数据的传输工作后,就会在传输层级别断开

连接,这样这个套接字就又可以重新提供给AcceptEx()使用。采用这种优化的方

法编程,将减轻那个专门做接受操作的线程创建套接字的压力(前文述及)。

这两个API也都有一个共同的弱点:Windows NT Workstation 或 Windows 2000 

专业版中,函数每次只能处理两个调用请求,只有在Windows NT、Windows 2000

服务器版、Windows 2000高级服务器版或 Windows 2000 Data Center中才获得完

全支持。

放在一起看看

以上各节中,我们讨论了开发高性能的、大响应规模的应用程序所需的函数、方

法和可能遇到的资源瓶颈问题。这些对你意味着什么呢?其实,这取决于你如何

构造你的服务器和客户端。当你能够在服务器和客户端设计上进行更好地控制时

,那么你越能够避开瓶颈问题。

来看一个示范的环境。我们要设计一个服务器来响应客户端的连接、发送请求、

接收数据以及断开连接。那么,服务器将需要创建一个监听套接字,把它与某个

完成端口进行关联,为每颗CPU创建一个工作线程。再创建一个线程专门用来发出

AcceptEx()。我们知道客户端会在发出连接请求后立刻传送数据,所以如果我们

准备好接收缓冲区会使事情变得更为容易。当然,不要忘记不时地轮询

AcceptEx()调用中使用的套接字(使用SO_CONNECT_TIME选项参数)来确保没有恶意

超时的连接。

该设计中有一个重要的问题要考虑,我们应该允许多少个AcceptEx()进行守候。

这是因为,每发出一个AcceptEx()时我们都同时需要为它提供一个接收缓冲区,

那么内存中将会出现很多被锁定的页面(前文说过了,每个重叠操作都会消耗一小

部分未分页内存池,同时还会锁定所有涉及的缓冲区)。这个问题很难回答,没有

一个确切的答案。最好的方法是把这个值做成可以调整的,通过反复做性能测试

,你就可以得出在典型应用环境中最佳的值。

好了,当你测算清楚后,下面就是发送数据的问题了,考虑的重点是你希望服务

器同时处理多少个并发的连接。通常情况下,服务器应该限制并发连接的数量以

及等候处理的发送调用。因为并发连接数量越多,所消耗的未分页内存池也越多

;等候处理的发送调用越多,被锁定的内存页面也越多(小心别超过了极限)。这

同样也需要反复测试才知道答案。

对于上述环境,通常不需要关闭单个套接字的缓冲区,因为只在AcceptEx()中有

一次接收数据的操作,而要保证给每个到来的连接提供接收缓冲区并不是太难的

事情。但是,如果客户机与服务器交互的方式变一变,客户机在发送了一次数据

之后,还需要发送更多的数据,在这种情况下关闭接收缓冲就不太妙了,除非你

想办法保证在每个连接上都发出了重叠接收调用来接收更多的数据。

结论

开发大响应规模的Winsock服务器并不是很可怕,其实也就是设置一个监听套接字

、接受连接请求和进行重叠收发调用。通过设置合理的进行守候的重叠调用的数

量,防止出现未分页内存池被耗尽,这才是最主要的挑战。按照我们前面讨论的

一些原则,你就可以开发出大响应规模的服务器应用程序。

画面程序,关于使用按钮和msgf的:【上一篇】
崔恺 像新首博一样平和:【下一篇】
【相关文章】
  • WinSock控件的使用(翻译原创)
  • TCL/EXPECT资源收集(最后更新2006/5/29)
  • winsock编程入门
  • Crystal Reports for Visual Studio 2005 5/30
  • 06/05/22 开发日记
  • 最新CU/400区精华帖子chm格式下载(2006/05/21)
  • 利用WinSock2 SPI进行网络内容访问控制
  • "本廠不收河南人"5/11
  • Asp.net2.0的安裝與必要條件5/10
  • 海南风光; 5/1没有出去玩的朋友,进来看看吧............
  • 【随机文章】
  • 大长今
  • Web服务器安全强化(思路)
  • PLM与企业信息化(三)如何建设PLM系统?
  • Oracle java存储过程在sqlplus中的调试信息显示
  • 15.12 The lock statementreleases the lock.
  • CommonC++ 应用之二:使用Get访问HTTP服务器
  • Linux下常见紧急情况的应急处理小贴士
  • Java容器集合学习心得
  • Linux 向全国推进
  • 通过光层实现IP over DWDM的业务保护
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 软讯网络 All Rigths Reserved.