700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Windows网络编程之(二)Socket通信非阻塞模式Select(TCP和UDP)

Windows网络编程之(二)Socket通信非阻塞模式Select(TCP和UDP)

时间:2023-02-11 00:05:35

相关推荐

Windows网络编程之(二)Socket通信非阻塞模式Select(TCP和UDP)

阻塞式的Socket很容易理解,但是使用起来非常别扭。Windows提供了选择(Select)I/O模型,进行异步Socket通信.

Select模型

int select(_In_ int nfds,//忽略. 此参数为了与Berkeley sockets兼容._Inout_ fd_set *readfds,//检查可读性fd_set指针._Inout_ fd_set *writefds,//检查可写性fd_set指针._Inout_ fd_set *exceptfds,//检查错误fd_set指针_In_ const struct timeval *timeout//超时);

本函数用于确定一个或多个套接口的状态。对每一个套接口,调用者可查询它的可读性、可写性及错误状态信息。用fd_set结构来表示一组等待检查的套接口。在调用返回时,这个结构存有满足一定条件的套接口组的子集,并且select()返回满足条件的套接口的数目。

下面是代码:

#include <Winsock2.h>#include <stdio.h>#include <process.h>static const int PORT = 7777;static const int BUFFER_LENGTH = 128 ;static int g_TotalConn = 0 ;static SOCKET g_ClientSocket[FD_SETSIZE] ;unsigned int __stdcall WorerkThread(void *);bool InitWSA() ;int main(){if(!InitWSA()){return -1 ;}SOCKET sockListen = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;SOCKADDR_IN addrSrv ;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK) ;addrSrv.sin_family = AF_INET ;addrSrv.sin_port = htons(PORT) ;bind (sockListen, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)) ;listen (sockListen, 3) ;_beginthreadex(NULL, 0, WorerkThread, NULL, 0, NULL) ;SOCKADDR_IN addrClient ;int len = sizeof (addrClient) ;while (true){SOCKET client = accept(sockListen, (SOCKADDR *)&addrClient, &len) ;g_ClientSocket[g_TotalConn++] = client ;}closesocket(sockListen) ;WSACleanup () ;return 0 ;}unsigned int __stdcall WorerkThread(void *){printf("线程begin:\n") ;int i;fd_set fdread;fd_set fdwrite;int ret;struct timeval tv = {1, 0};char szMessage[BUFFER_LENGTH];while (true){FD_ZERO(&fdread);FD_ZERO(&fdwrite);for (i = 0; i < g_TotalConn; i++){FD_SET(g_ClientSocket[i], &fdread) ;FD_SET(g_ClientSocket[i], &fdwrite) ;}ret = select(0, &fdread, &fdwrite, NULL, &tv);/*if(g_TotalConn > 0 && ret == SOCKET_ERROR){printf("Socket:an error occurred!\n") ;}*/if (ret == 0){printf("超时\n") ;continue ;}for (i = 0; i < g_TotalConn; i++){if (FD_ISSET(g_ClientSocket[i], &fdread)){ret = recv(g_ClientSocket[i], szMessage, BUFFER_LENGTH, 0);if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)){printf("Client socket %d closed.\n", i);closesocket(g_ClientSocket[i]);g_ClientSocket[i] = 0 ;if(i != g_TotalConn -1){g_ClientSocket[i--] = g_ClientSocket[g_TotalConn -1] ;}g_TotalConn-- ;}else{szMessage[ret] = '\0';send(g_ClientSocket[i], szMessage, strlen(szMessage), 0);printf("发送数据给Client:%s\n", szMessage) ; }}if (FD_ISSET(g_ClientSocket[i], &fdwrite)){//可以发送数据}}}printf("线程end:\n") ;return 0 ;}bool InitWSA(){WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 2, 2 );err = WSAStartup( wVersionRequested, &wsaData );if ( err != 0 ) { return false ;}if ( LOBYTE( wsaData.wVersion ) != 2 ||HIBYTE( wsaData.wVersion ) != 2 ) {WSACleanup();return false ; }return true ;}

特点:

1、程序可能阻塞在select处一段指定的时间。

2、使用轮循的方式,检测Socket是否可读或可写、效率低下。

点评:虽然实现了异步IO,但是实现方式“扭曲”,效率低下,不推荐使用,尤其是服务端。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。