Windows上如何玩非阻塞的connect ---让程序员自定义connect函数的超时时间

               

        我们知道, 对于阻塞的socket而言, connect函数也是阻塞的, 我在Windows上测试过, 对于阻塞的socket而言, connect的阻塞时间约为25s(linux上是75s吧, 各个平台都不一样).  也就是说, 很多时候, 客户端需要等25s才继续往下执行。 我们想象一下, 用户肯定会不满意啊, 得罪了用户, 那就糟糕了。 那能不能搞个自己设置超时时间的connect函数呢? 完全可以! 在本文中, 我们来学习一下非阻塞connect函数的实现---让程序员自定义connect函数的超时时间。

       说明: 两年后, 当我再次审视这些程序的时候, 我发现, select后, 强烈建议做FD_ISSET检查。


       直接上客户端的代码:

#include <stdio.h>#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")int main()// 网络初始化 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup( wVersionRequested, &wsaData ); // 创建客户端socket(默认为是阻塞socket) SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); // 设置为非阻塞的socket int iMode = 1; ioctlsocket(sockClient, FIONBIO, (u_long FAR*)&iMode);  // 定义服务端 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(8888); // 超时时间 struct timeval tm; tm.tv_sec  = 5; tm.tv_usec = 0int ret = -1;  // 尝试去连接服务端 if (-1 != connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))) {  ret = 1; // 连接成功 } else {  fd_set set;  FD_ZERO(&set);  FD_SET(sockClient, &set);  if (select(-1, NULL, &set, NULL, &tm) <= 0)  {   ret = -1; // 有错误(select错误或者超时)  }  else  {   int error = -1;   int optLen = sizeof(int);   getsockopt(sockClient, SOL_SOCKET, SO_ERROR, (char*)&error, &optLen);       // 之所以下面的程序不写成三目运算符的形式, 是为了更直观, 便于注释   if (0 != error)   {    ret = -1; // 有错误   }   else   {    ret = 1// 无错误   }  } } // 设回为阻塞socket iMode = 0; ioctlsocket(sockClient, FIONBIO, (u_long FAR*)&iMode); //设置为阻塞模式 // connect状态 printf("ret is %d\n", ret); // 发送数据到服务端测试以下 if(1 == ret) {  send(sockClient, "hello world", strlen("hello world") + 1, 0); } // 释放网络连接 closesocket(sockClient); WSACleanup(); return 0;}


      我们先不管服务端, 直接运行上面的程序, 过5s后, 程序结果为:ret is -1


      好, 我们关掉当面的客户端。 并启用下面的服务端:

#include <stdio.h>#include <winsock2.h> // winsock接口#pragma comment(lib, "ws2_32.lib") // winsock实现int main(){ WORD wVersionRequested;  // 双字节,winsock库的版本 WSADATA wsaData;         // winsock库版本的相关信息  wVersionRequested = MAKEWORD(1, 1); // 0x0101 即:257  // 加载winsock库并确定winsock版本,系统会把数据填入wsaData中 WSAStartup( wVersionRequested, &wsaData );  // AF_INET 表示采用TCP/IP协议族 // SOCK_STREAM 表示采用TCP协议 // 0是通常的默认情况 unsigned int sockSrv = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_family = AF_INET; // TCP/IP协议族 addrSrv.sin_addr.S_un.S_addr = inet_addr("0.0.0.0"); // socket对应的IP地址 addrSrv.sin_port = htons(8888); // socket对应的端口 // 将socket绑定到某个IP和端口(IP标识主机,端口标识通信进程) bind(sockSrv,(SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); // 将socket设置为监听模式,5表示等待连接队列的最大长度 listen(sockSrv, 5); SOCKADDR_IN addrClient; int len = sizeof(SOCKADDR); unsigned int sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len); printf("To receive...\n"); char recvBuf[100] = {0}; recv(sockConn, recvBuf, 100, 0); // 接收客户端数据,最后一个参数一般设置为0 printf("recv is %s\n", recvBuf); while(1); closesocket(sockConn);  closesocket(sockSrv); WSACleanup();  return 0;}


     然后呢, 我们再启动客户端, 发现客户端立即出现:ret is 1, 服务端对应的结果为:

To receive...
recv is hello world


       由此可见, 上面的客户端程序实现了非阻塞的connect, 也就是用, 程序员可以自定义超时时间。 ok, 先这样。


           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自blog.csdn.net/sjhfkhsf/article/details/87624724