c++ programmer
分类: C/C++
2016-12-25 16:02:51
1.相关函数和数据结构
① int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout )
nfds:一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,在windows系统中被忽略。
readfds:指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化,即我们关心是否可以从这些文件中读取数据了,可以传入NULL值,表示不关心任何文件的读变化。
writefds:指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化,即我们关心是否可以向这些文件中写入数据了,可以传入NULL值,表示不关心任何文件的写变化。
exceptfds:同上面两个参数的意图,用来监视文件错误异常。
timeout:select的超时时间,它可以使select处于三种状态,第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非 阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;第三,timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回。
返回值:负值:select错误;
正值:某些文件可读写或出错,值为准备就绪的描述符数;
0:等待超时,没有可读写或错误的文件。
注意:select返回时,无论返回值为何值,内核都会清除fd_set中IO未就绪的套接字,只保留IO就绪的套接字。故返回0时,fd_set中套接字数量也为0。
② FD_ZERO(fd_set*):清空fd_set。
FD_SETSIZE(fd_set*):获取fd_set中套接字的个数。
FD_SET(SOCKET,fd_set*):将某套接字加入到fd_set中。
FD_CRL(SOCKET,fd_set*):从fd_set中删除某套接字。
FD_ISSET(SOCKET,fd_set*):判断某套接字是否在fd_set中。
③ timeval: 超时值结构体数据。
2.编程流程(server)
① 创建套接字(socket);
② 绑定本地地址(bind);
③ 监听套接字(listen);
④ 定义fd_set数据,并将监听套接字加入到fd_set(fd_set,FD_ZERO,FD_SET);
⑤ 另一线程调用select等待IO就绪(select);
⑥ 判断监听套接字是否在fd_set中,接受连接或在客户端套接字上读写数据(FD_ISSET,accept,recv,send);
⑦ 清空fd_set,将监听套接字和客户端套接字加入到fd_set中;
⑧ 循环调用⑤-⑦。
3.优缺点及适用场景
优点:
① 可以在单线程中对多个套接字进行操作,消耗资源少;
② 跨平台性好,方便移植性。
缺点:
① 默认最多同时支持64个套接字;
② 实时性不够,非并发。
适用场景:
1.相关函数和数据结构
① int WSAEventSelect(SOCKET socketObject, WSAEVENT hEventObject, long lNetworkEvents)
socketObject: 目标套接字,将与事件对象绑定。
hEventObject: 目标时间对象,将与套接字绑定。
inetworkEvent:网络事件标志组合,标志相关类型IO操作就绪时,事件自动置为有信号状态。
返回值:成功返回0,失败返回SOCKET_ERROR。
② int WSAEnumNetworkEvents (SOCKET sockObject, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents, LPINT lpiCount)
sockObject:与事件对象绑定的套接字。
hEventObject:与套接字绑定的事件对象。
lpNetworkEvents:WSANETWORKEVENTS结构的数组,每一个元素记录了一个网络事件和相应的错误代码。
lpiCount:中的元素数目。在返回时,本参数表示中的实际元素数目;如果返回值是WSAENOBUFS,则表示为获取所有网络事件所需的元素数目。
返回值:成功返回0,失败返回SOCK_ERROR。
③ DWORD WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT FAR * lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable )
cEvents:指出lphEvents所指数组中句柄的数目。句柄的最大值为WSA_MAXIMUM_WAIT_EVENTS。
lphEvents:指向一个句柄的。
fWaitAll:指定等待类型。若为真TRUE,则当lphEvents中的所有同时有信号时,返回。若为假FALSE,则当任意一个有信号时即返回。在后一种情况下,返回值指出是哪一个造成返回。
dwTimeout:指定超时时间间隔(以毫秒计)。当超时间隔到,即返回,不论fWaitAll参数所指定的条件是否满足。如果dwTimeout为零,则测试指定的的状态,并立即返回。如果dwTimeout是WSA_INFINITE,则的超时间隔永远不会到。
fAlertable:指定当系统将一个输入/输出完成例程放入队列以供执行时,是否返回。若为真TRUE,则返回且执行完成例程。若为假FALSE,不返回,不执行完成例程。
返回值:成功,返回IO准备就绪的套接字对应的事件的索引;失败,返回WSA_WAIT_FAILED。
2.编程流程
① 创建套接字(socket);
② 绑定本地地址(bind);
③ 监听套接字(listen);
④ 定义存放套接字和事件的容器,创建事件对象,并将其与监听套接字绑定(WSACreateEvent,WSAEventSelect);
⑤ 另一线程调用WSAWaitForMultipleEvents等待事件触发;
⑥ 循环遍历事件容器,对有信号的事件及对应套接字,调用WSAEnumNetworkEvents 取出其对应就绪的IO操作,并进行处理;
⑦ 若为FD_ACCEPT,则创建新的套接字和事件对象,加入到对应容器中;
⑧ 重复⑤-⑦。
3.优缺点及适用场景
优点:
① 相对于select的主动查询,事件模型为被动通知,不需要一直轮询,并且具备较高的实时性。
缺点:
① WSAWaitForMultipleEvents最多支持64个事件对象的监听,若要增加,则需另外开辟线程,增加线程上下文切换的资源消耗。
适用场景:
1.相关函数和数据结构
① BOOL WSAGetOverlappedResult(SOCKET socketObject, LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer, BOOL fWait, LPDWORD lpdwFlags)
socketObject:套接字。
lpOverlapped:重叠IO数据结构,OVERLAPPED。
lpcbTransfer:接受或发送数据的字节数。
fWait:等待标志,TURE一直等待,FALSE立即返回。
lpdwFlags:接受返回标志,当投递的操作为WSARecv时,一定不能为NULL。
返回值:成功:返回TRUE;失败:返回FALSE。
② typedef struct _WSAOVERLAPPED
{
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union
{
struct { DWORD Offset; DWORD OffsetHigh; };
PVOID Pointer;
};
HANDLE hEvent;
} WSAOVERLAPPED, *LPWSAOVERLAPPED;
2.编程流程
① 创建套接字(socket);
② 绑定本地地址(bind);
③ 监听套接字(listen);
④ 接受连接(accept;)
⑤ 定义OVERLAPPED数据结构;
⑥ 投递WSARecv,WSASend等异步操作;
⑦ 调用SleepEx,如果不调用该函数,系统将无法调用完成例程函数。
⑧ 循环遍历事件容器,对有信号的事件及对应套接字和重叠IO数据,
⑨ 重复⑥-⑧。
3.优缺点及适用场景
优点:
① 可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口只是支持NT系统。
② 比起阻塞、select、WSAAsyncSelect以及WSAEventSelect等模型,重叠I/O(Overlapped I/O)模型使应用程序能达到更佳的系统性能。因为它和这4种模型不同的是,使用重叠模型的应用程序通知缓冲区收发系统直接使用数据。
缺点:
① 单线程最多支持64个事件,增加线程,需考虑线程上下文切换的代价。
1.相关函数和数据结构
2.编程流程
① 创建套接字(socket);
② 绑定本地地址(bind);
③ 监听套接字(listen);
④ 定义存放套接字和事件的容器,创建事件对象;
⑤ 定义OVERLAPPED数据结构,将事件对象绑定到OVERLAPPED数据;
⑥ 投递AeecptEx,WSARecv,WSASend等异步操作;
⑦ 另一线程调用WSAWaitForMultipleEvents等待事件触发;
⑧ 循环遍历事件容器,对有信号的事件及对应套接字和重叠IO数据,
⑨ 重置OVERLAPPED套接字的Event对象(WSAResetEvent);
⑩ 查看重叠操作结果,做相处理(WSAGetOverlappedResult);
① 重复⑥-⑩。
3. 优缺点及适用场景
1.相关函数和数据结构
① HANDLE CreateIoCompletionPort( HANDLE ileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, WORD NumberOfConcurrentThreads)
ileHandle: 一个必须支持支持重叠IO操作的句柄,socket需强制转换成HANDLE。可以为INVALID_HANDLE_VALIE,为INVALID_HANDLE_VALIE时创建一个完成端口对象,不为INVALID_HANDLE_VALIE时,将一个handle与完成端口绑定。
ExistingCompletionPort: 将要与句柄绑定的目标完成端口,当句柄为空时,函数功能为创建一个完成端口,该值也必须为NULL。
CompletionKey: 传递给完成端口处理线程的线程参数,若函数功能为创建一个完成端口时,须为NULL。
NumberOfConCurrentThreads: 完成端口可调用的最大线程数。当函数功能为绑定一个句柄到完成端口时,该参数被忽略,该参数为0时,系统自动调用尽可能多的线程来处理完成端口操作。
返回值:成功:返回一个新的完成端口或者目标绑定完成端口,失败:返回NULL。
② BOOL GetQueuedCompletionStatus(HANDLE CompletionPort, LPDWORD lpNumberOfBytes, PULONG_PTR lpCompletionKey, LPOVERLAPPED *lpOverlapped, DWORD dwMilliseconds)
CompletionPort:等待重叠IO操作就绪的完成端口对象。
lpNumberOfBytes:完成的重叠IO操作的字节数。
lpCompletionKey:CreateIoCompletionPort中绑定的线程参数。
lpOverlapped:重叠IO操作投递时绑定的OVERLAPPED数据结构。
dwMilliseconds:超时时间。
返回值:成功:返回TRUE;失败:返回FALSE。
③ BOOL PostQueuedCompletionStatus(HANDLE CompletionPort, DWORD dwNumberOfBytesTransferred, ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped)
CompletionPort:完成端口。
dwNumberOfBytesTransferred:传递给GetQueuedCompletionStatus的IO操作字节数的参数。
dwCompletionKey:传递给GetQueuedCompletionStatus的线程参数的参数。
lpOverlapped:传递给GetQueuedCompletionStatus的OVERLAPPED的参数。
返回值:成功:返回非0;失败:返回0。
④ BOOL AcceptEx(SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength, LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped)
sListenSocket:监听套接字。
sAcceptSocket:接受连接客户端套接字。
lpOutputBuffer:接收数据的buffer,包含第一次发送的数据,本地地址信息,远程地址信息。
dwReceiveDataLength:接收数据部分的的长度,值为sizeof(lpOutputBuffer) - 2*(sizeof(SOCKADDR)+16)。
dwLocalAddressLength:本地地址长度,值为sizeof(SOCKADDR)+16。
dwRemoteAddressLength:远端地址长度,值为sizeof(SOCKADDR)+16。
lpdwBytesReceived:接收到的字节数。
lpOverlapped:本次操作绑定的重叠IO数据结构。
返回值:成功::返回TRUE;失败:返回FALSE。
⑤ void GetAcceptExSockaddrs(PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, DWORD dwRemoteAddressLength, LPSOCKADDR *LocalSockaddr,
LPINT LocalSockaddrLength, LPSOCKADDR *RemoteSockaddr, LPINT RemoteSockaddrLength)
lpOutputBuffer:AccepEx中用于接受数据的buffer。
dwReceiveDataLength:接收数据部分的的长度,值为sizeof(lpOutputBuffer) - 2*(sizeof(SOCKADDR)+16)。
dwLocalAddressLength:本地地址长度,值为sizeof(SOCKADDR)+16。
dwRemoteAddressLength:远端地址长度,值为sizeof(SOCKADDR)+16。
LocalSockaddr:接收本地地址。
LocalSockaddrLength:接收到本地地址的长度。
RemoteSockaddr:接收远程地址。
RemoteSockaddrLength:接收到远程地址的长度。
⑥ BOOL TransmitFile(SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend,
LPOVERLAPPED lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwReserved)
hSocket:传输文件使用的套接字。
hFile:文件句柄。
nNumberOfBytesToWrite:指定需要传输的字节数,若要传输整个文件,设置为0。
nNumberOfBytesPerSend:每次返送的数据块的大小,使用默认大小,设置为1。
lpOverlapped:绑定OVERLAPEED数据结构。
lpTransmitBuffers:在文件发送之前和发送完成之后要发送的数据。
dwReserved:指定传输标识。
返回值:成功:返回true;失败:返回false。
注意:使用TransmitFile传输文件时,文件传输将一直在内核状态下进行,从而避免了使用WSASend,ReadFile等操作产生的用户态和内核态之间的频繁状态切换。
2.编程流程
① 创建套接字(WSASocket,必须指定WSA_FALG_OVERLAPPED标识);
② 创建完成端口并与套接字绑定(CreateIoCompletionPort);
③ 绑定本地地址(bind);
④ 监听套接字(listen);
⑤ 投递ACCEPT操作(AcceptEx,OVERLAPPED);
⑥ 各处理线程调用GetQueuedCompletionStatus等待重叠IO-ACCPET操作完成;
⑦ 接受客户端连接,将与客户端通信的套接字与完成端口绑定,继续投递ACCEPT操作(CreateIoCompletionPort,AcceptEx,OVERLAPPED);
⑧ 根据需求,接收或发送数据到客户端(WSARecv,WSASend);
⑨ 重复⑥-⑧。
⑨ 传递关闭信息给各个处理线程,释放相关资源(PostQueuedCompletionStatus)。
3.优缺点及适用场景
优点:
① 无并发上限限制;
② 在收到通知时数据已经收发完成,处理效率高;
③ cpu负载均衡。
缺点:
① 只适合windows NT及以上平台。
适用场景:大并发服务器。