• WinSocket 非阻塞之select用法


    winSocket下有4个非阻塞的方式;

    select模型是winSocket下最常见的i/o模型,通过select可以判断是否存在一个或多个有效的socket连接状态,判断套接字是否可以读取或者写入。他既能防止socket处于阻塞状态下时候,最后一次io操作以后进入阻塞状态,也可以套接字处于非阻塞状态下出现的wsaewouldblock错误,

    select  函数原型:

    int select (
      int nfds, //用来与Berkely socket兼容, 通常写0   fd_set* readfds, //检查可读性的socket集合   fd_set* writefds, //检查可写性的socket集合   fd_set* exceptfds,//检查异常的socket集合   const struct timeval* timeout // 设置超时时间 
    );
    
    返回值:
        readfds, writefds, exceptfds中被检查复合条件的socket总数。
     
    注意:
       由于select每次返回时,readfds, writefds, exceptfds都会被改变,所以,下次调用select前,要重新初始化fds。
    对于三种检查各自如下:
    readfds:
    > 若当前socket处在listen状态,则有个连接到来,调用accept将成功建立连接
    >若连接已经建立,则意味着有新数据到来,此时可以调用recv接收数据
    >对方连接终止,调用recv,根据返回值判断是否是正常终止: 0 对方正常终止, ErrorCode 对方重置连接或强制断开连接
    writefds:
    >当前socket调用了connect, 则成功连接
    >当前socket调用了send,则能成功发送出去
    exceptfds:
    >当前socket调用connect,则连接失败
    >OOB 数据可读(暂时没研究,OOB是什么个东东)
    以下附上简单的测试代码:
     
    设置socket为非阻塞模式的时候要先设置
     
    int status = ioctlsocket(socket s,FIOBIO,&cmd);
    如果status 不等于socket_error表示非阻塞模式设置成功
     
    server端代码:
     

    #include "SocketInit.h"
    #include "iostream"
    using namespace std;

    CInitSock sockInit;

    int main()
    {
     SOCKET s = SocketFactory::getTCPSocket();
     
     hostent *thisHost = gethostbyname("");
     char *localIP = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
     const int localIPInt = inet_addr(localIP);
     const unsigned short linkPort = ntohs(4001);//本地监听

     sockaddr_in servAddr;
     servAddr.sin_family = AF_INET;
     servAddr.sin_port = linkPort;
     servAddr.sin_addr.S_un.S_addr = localIPInt;

     ::bind(s, (sockaddr *)&servAddr, sizeof(servAddr));
     ::listen(s, 1);

     sockaddr_in clientAddr;
     int lenC = sizeof(clientAddr);

     cout<<"TCP server: "<<endl;
     SOCKET clientSocket = ::accept(s, (sockaddr *)&clientAddr, &lenC);
     cout<<"Recv a connection..."<<endl;

     timeval waitTime;
     waitTime.tv_sec=2;
     waitTime.tv_usec=0;
     while(true)
     {
      fd_set fdSocket;
      FD_ZERO(&fdSocket);
      FD_SET(clientSocket, &fdSocket);

      int nRet = ::select(0, &fdSocket, 0, 0, &waitTime);
      if(nRet<0)
      {
       cout<<"Faild Select()"<<endl;
       exit(-1);
      }
      else if(nRet ==0)
      {
       cout<<"time out()"<<endl;
       continue;
      }
      else
      {
       if(FD_ISSET(clientSocket, &fdSocket))
       {
        char rBuff[100];
        int nRec=::recv(clientSocket, rBuff, 100, 0);
        cout<<"Recv from client data: "<<nRec<<endl;
        if(nRec < 0)
        {
         cout<<"Not normal close: "<<::GetLastError()<<endl;
         break;
        }
        else if(nRec == 0)
        {
         cout<<"Normal close"<<endl;
         break;
        }
        else
        {
         rBuff[nRec]=0;
         cout<<"Data : "<<rBuff<<endl;
        }

       }
      }
     }

     ::closesocket(clientSocket);
     ::closesocket(s);

     return 0;
    }

    客户端代码;

    #include "SocketInit.h"
    #include "iostream"
    using namespace std;

    CInitSock sockInit;
    int main()
    {
     
     SOCKET s = SocketFactory::getTCPSocket();

     hostent *thisHost = gethostbyname("");
     char *localIP = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
     const int localIPInt = inet_addr(localIP);
     const unsigned short linkPort = ntohs(4001);//本地监听

     sockaddr_in servAddr;
     servAddr.sin_family = AF_INET;
     servAddr.sin_port = linkPort;
     servAddr.sin_addr.S_un.S_addr = localIPInt;

     cout<<"Client : "<<endl;
     if(::connect(s, (sockaddr *)&servAddr, sizeof(servAddr)) == -1)
     {
      printf("Faild connect(): %d\n", ::GetLastError());
      return 0;
     }

     char sendStr[100];
     while(true)
     {
      cout<<"Input send data('q' to normal quit): ";
      cin.getline(sendStr, 100);
      if(sendStr[0]=='q') break;
       ::send(s, sendStr, strlen(sendStr), 0);
     }

     ::closesocket(s);

     return 0;
    }

    本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。

  • 相关阅读:
    宏队列与微队列
    async 与 await
    promise关键点
    promiseAPI
    promise基本使用
    JS中的错误(Error)即错误处理
    两种类型的回调函数(同步回调与异步回调)
    区别实例对象与函数对象
    在二叉树中查找指定值结点的所有祖先
    关于js点击事件出现 xx is not defined at HTMLAnchorElement.onclick 的问题
  • 原文地址:https://www.cnblogs.com/zjypp/p/2319407.html
Copyright © 2020-2023  润新知