|
|
(AcceptEx原形,加粗的即为需要传入的socket
BOOL AcceptEx(
SOCKET sListenSocket,
SOCKET sAcceptSocket,
PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
LPDWORD lpdwBytesReceived,
LPOVERLAPPED lpOverlapped
);
)
使用AcceptEx的例程可能是这个样子的:
do {
-Wait for a previous AcceptEx to complete //等待前一个AcceptEx完成
-Create a new socket and associate it with the completion port //创建一个新的Socket并将其关联
//到完成端口
-Allocate context structure etc. //初始化相关的环境信息结构
-Post an AcceptEx request. //进入AcceptEx请求。
}while(TRUE);
一个服务器一直具备足够的AcceptEx调用,这样就可以立刻响应客户机的连接。AcceptEx操作的数量取决于服务器的策略。如果要满足高连接率(比如大量的短暂连接或爆发性的流量)的话,当然比不常发生连接的程序需要更多的AcceptEx入口。聪明的策略就是根据流量改变AcceptEx调用的数量,而避免只使用一个确定的数目。
在Win2000上,Winsock提供了一些帮助,用来判断AcceptEx调用的数量是否跟不上需要。当创建一个监听Socket之后,使用WSAEventSelect函数把它和一个FD_ACCEPT事件关联,如果没有accept未决的调用正在进行,一旦有请求到来,该事件(FD_ACCEPT)就会发生。因此此事件可以用来告诉开发人员:还需要进行更多的AcceptEx操作,或者由此探测到一个有异常行为的远端实体。注意:此机制在NT上是无效的。
使用AcceptEx的显著好处是:在一次连接中就可以获取客户端的数据,见AcceptEx的lpOutputBuffer参数。这意味着如果客户端连接并立刻发送数据的话,AcceptEx将在客户端连接成功和数据发送之后才完成。这个功能同时导致的问题是:AcceptEx必须等待数据接受完成才能返回。因为一个带Output缓冲的AcceptEx函数并非一个“原子”操作,而是两步的过程:接受连接和等待数据。所以程序在数据接受之前并不会知道连接成功。当然客户端也可以连接到服务器而不马上发送数据,如果这样的连接过多,服务器将开始拒绝合法的连接,因为没有可用的未决的Accept操作入口。这也是一种常用的方法,通过拒绝访问,防止恶意攻击和海量连接。
在正在接受连接的线程中,可以检查AcceptEx调用传入的socket,调用getsockopt检查其SO_CONNECT_TIME,该值返回的是socket连接的时间,没有连接的时候返回-1。
根据WSAEventSelect机制所带来的特性,我们可以很容易的判断是否应该检查传到AcceptEx函数的socket句柄的连接时间。如果在一定时间里,AcceptEx没有从某个连接中收到数据,AcceptEx可以通过关闭该socket来断开连接。在不紧急的情况下,程序不应该关闭一个AcceptEx里处于未连接状态的socket ,因为系统考虑到性能问题,关联在AcceptEx上的内核态数据结构不会被释放,直到一个新的连接到来或监听socket本身都关闭了。
乍看起来,一个发出AcceptEx请求的线程同时也可以是一个关联在完成端口上,并且处理其他完成IO事件的工作线程。然而,最好不要设计这样一个线程。在winsocket2的层次结构上有一个副作用,那就是一个socket/WSASocket API的开销是相当可观的,每个AccepEx都需要创建一个新的socket,所以最好创建一个单独的跟其他IO处理无关的线程来调用AcceptEx。当然,你还可以利用这个线程来进行其他的工作如创建事件log
关于AcceptEx要注意的最后一个事情是:Winsock2的其他供应商不一定会实现AcceptEx函数。同样情况也包括的其他Microsoft的特定APIs如TransmitFile,GetAcceptExSockAddrs以及其他Microsoft将在以后版本的windows里。在运行WinNT和Win2000的系统上,这些APIs在Microsoft提供的DLL(mswsock.dll)里实现,可以通过链接mswsock.lib或者通过WSAioctl的SIO_GET_EXTENSION_FUNCTION_POINTER操作动态调用这些扩展APIs.
未获取函数指针就调用函数(如直接连接mswsock..lib并直接调用AcceptEx)的消耗是很大的,因为AcceptEx 实际上是存在于Winsock2结构体系之外的。每次应用程序常试在服务提供层上(mswsock之上)调用AcceptEx时,都要先通过WSAIoctl获取该函数指针。如果要避免这个很影响性能的操作,应用程序最好是直接从服务提供层通过WSAIoctl先获取这些APIs的指针。
TransmitFile 和TransmitPackets函数
Winsock提供了两个专为文件和内存数据传输而优化过的函数。TransmitFile API在WinNT和Win2000均有效,而TransmitPackets作为一个新的扩展函数,将在未来版本的windows里实现。
TransmitFile可以把文件的内容通过socket传输。一般情况下,如果应用程序通过socket传输文件,首先要用CreateFile打开文件,并循环调用ReadFile和WSASend函数,读取一段数据然后发送,直到整个文件发送完毕。这样的效率很低,因为ReadFile和WSASend调用都需要系统在用户态和核心态之间进行转换。T
上一页 [1] [2] [3] [4] [5] [6] 下一页
网友评论:(评论内容只代表网友观点,与本站立场无关!) |
阅读排行
|