8_1――非阻塞模式(ioctlsocket)

 

  
  
  
  
  1. //Server.cpp  
  2. #include <stdio.h>  
  3. #include <winsock2.h>             //winsock.h (2种套接字版本)  
  4. #pragma comment(lib,"ws2_32.lib") //wsock32.lib  
  5.  
  6. #define MAXSIZE 100 //  
  7.  
  8. int main()  
  9. {  
  10.     //  
  11.     int retVal;  
  12.  
  13.     char buf[MAXSIZE];  
  14.  
  15.     //初始化套接字库  
  16.     WORD wVersionRequest;  
  17.     WSADATA wsadata;  
  18.  
  19.     wVersionRequest=MAKEWORD(2,2);  
  20.  
  21.     retVal=WSAStartup(wVersionRequest,&wsadata);  
  22.     if(retVal == SOCKET_ERROR)  
  23.     {  
  24.         printf("WSAStartup failed!");  
  25.  
  26.         return -1;  
  27.     }  
  28.  
  29.     //创建套接字  
  30.     SOCKET sServer;  
  31.     sServer=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  
  32.     if(sServer == INVALID_SOCKET)  
  33.     {  
  34.         printf("socket failed!");  
  35.  
  36.         WSACleanup();  
  37.         return -1; //每次检测到失败后,即需要返回  
  38.     }  
  39.  
  40.     //设置为非阻塞模式  
  41.     int imode=1;  
  42.     retVal=ioctlsocket(sServer,FIONBIO,(u_long *)&imode);  
  43.     if(retVal == SOCKET_ERROR)  
  44.     {  
  45.         printf("ioctlsocket failed!");  
  46.  
  47.         closesocket(sServer);  
  48.         WSACleanup();  
  49.         return -1;  
  50.     }  
  51.  
  52.     //绑定套接字并将其设置为监听状态  
  53.     SOCKADDR_IN addrServ;  
  54.     addrServ.sin_family=AF_INET;  
  55.     addrServ.sin_port  =htons(5000);  
  56.     addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102");  
  57.  
  58.     retVal=bind(sServer,(SOCKADDR *)&addrServ,sizeof(addrServ)); //绑定套接字到某一个具体的服务器  
  59.     if(retVal == SOCKET_ERROR)  
  60.     {  
  61.         printf("bind failed!");  
  62.  
  63.         closesocket(sServer);  
  64.         WSACleanup();  
  65.         return -1;  
  66.     }  
  67.  
  68.     retVal=listen(sServer,1); //第二个参数,表示最大连接数目  
  69.     if(retVal == SOCKET_ERROR)  
  70.     {  
  71.         printf("listen failed!");  
  72.  
  73.         closesocket(sServer);  
  74.         WSACleanup();  
  75.         return -1;  
  76.     }  
  77.  
  78.  
  79.     //接受连接  
  80.     sockaddr_in addrClient; //定义一个临时地址,用于接受连接(注意:某个客户端由Client.cpp确定)  
  81.     int len=sizeof(sockaddr_in);  
  82.  
  83.     SOCKET sClient;  
  84.     int errcode;  
  85.  
  86.     while(true)  
  87.     {  
  88.         sClient=accept(sServer,(sockaddr *)&addrClient,&len);  
  89.         if(sClient == INVALID_SOCKET)  
  90.         {  
  91.             errcode=WSAGetLastError();  
  92.             if(errcode == WSAEWOULDBLOCK)  //表示没有客户端发起连接,继续循环  
  93.             {  
  94.                 Sleep(100);  
  95.                 continue;  
  96.             }  
  97.             else 
  98.             {  
  99.                 printf("accept failed!");  
  100.  
  101.                 closesocket(sServer); //连接失败,关闭服务器套接字并释放套接字库  
  102.                 WSACleanup(); //  
  103.                 return -1;  
  104.             }  
  105.         }  
  106.  
  107.         break//  
  108.     }  
  109.  
  110.     //接收数据  
  111.     while(true)  
  112.     {  
  113.         retVal=recv(sClient,buf,strlen(buf),0);  
  114.         if(retVal == SOCKET_ERROR)  
  115.         {  
  116.             errcode=WSAGetLastError(); //这个变量errcode没有重复定义吗?  
  117.             if(errcode == WSAEWOULDBLOCK)  //  
  118.             {  
  119.                 Sleep(100);  
  120.                 continue;  
  121.             }  
  122.             else 
  123.             {  
  124.                 if(errcode==WSAETIMEDOUT || errcode==WSAENETDOWN)  
  125.                 {  
  126.                     closesocket(sClient);  
  127.                     closesocket(sServer);  
  128.                     WSACleanup();  
  129.                     return -1;  
  130.                 }  
  131.             }  
  132.         }  
  133.  
  134.         if(buf == "quit"//如果接收数据为"quit",则发送回显"quit"  
  135.         {  
  136.             retVal=send(sClient,buf,strlen(buf),0);  
  137.             break;  
  138.         }  
  139.         else 
  140.         {  
  141.             //发送数据  
  142.             while(true)  
  143.             {  
  144.                 retVal=send(sClient,buf,strlen(buf),0); //a.回显接收数据;b.第四个参数:0?  
  145.                 if(retVal == SOCKET_ERROR)  //错误处理  
  146.                 {  
  147.                     errcode=WSAGetLastError();  
  148.                     if(errcode == WSAEWOULDBLOCK)  //  
  149.                     {  
  150.                         Sleep(100);  
  151.                         continue;  
  152.                     }  
  153.                     else 
  154.                     {  
  155.                         closesocket(sClient);  
  156.                         closesocket(sServer);  
  157.                         WSACleanup();  
  158.                         return -1;  
  159.  
  160.                     }  
  161.                 }  
  162.  
  163.                 break//如果发送数据成功,则退出循环  
  164.             }  
  165.  
  166.         }  
  167.     }  
  168.  

 

  
  
  
  
  1. //Client.cpp  
  2. #include <stdio.h>  
  3. #include <WinSock2.h> //winsock.h  
  4. #pragma comment(lib,"ws2_32.lib"); //wsock32.lib  
  5.  
  6. #include <iostream>  
  7. using namespace std;  
  8.  
  9. #include <string.h> //strcpy函数  
  10.  
  11. #define MAXSIZE 100 //  
  12.  
  13. int main()  
  14. {  
  15.     //  
  16.     int retVal;  
  17.  
  18.     char buf[MAXSIZE];  
  19.  
  20.     //初始化套接字库  
  21.     WORD wVersionRequest;  
  22.     WSADATA wsadata;  
  23.  
  24.     wVersionRequest=MAKEWORD(2,2);  
  25.  
  26.     retVal=WSAStartup(wVersionRequest,&wsadata);  
  27.     if(retVal == SOCKET_ERROR)  
  28.     {  
  29.         printf("WSAStartup failed!");  
  30.  
  31.         return -1;  
  32.     }  
  33.  
  34.     //创建套接字  
  35.     SOCKET sClient;  
  36.     sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  
  37.     if(sClient == INVALID_SOCKET)  
  38.     {  
  39.         printf("socket failed!");  
  40.  
  41.         WSACleanup();  
  42.         return -1; //每次检测到失败后,即需要返回  
  43.     }  
  44.  
  45.     //设置为非阻塞模式  
  46.     int imode=1;  
  47.     retVal=ioctlsocket(sClient,FIONBIO,(u_long *)&imode);  
  48.     if(retVal == SOCKET_ERROR)  
  49.     {  
  50.         printf("ioctlsocket failed!");  
  51.  
  52.         closesocket(sClient);  
  53.         WSACleanup();  
  54.         return -1;  
  55.     }  
  56.  
  57.  
  58.     //发起连接  
  59.     sockaddr_in addrServ;  
  60.     addrServ.sin_family=AF_INET; //表示使用的是,TCP/IP地址家族  
  61.     addrServ.sin_port  =htons(5000); //为什么要使用htons宏?  
  62.     addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102");  
  63.  
  64.     int len=sizeof(sockaddr_in); //sizeof只是一个运算符,不是函数  
  65.  
  66.     while(true)  
  67.     {  
  68.         retVal=connect(sClient,(sockaddr *)&addrServ,len); //连接到某一个具体的服务器  
  69.         if(retVal == INVALID_SOCKET)  
  70.         {  
  71.             int errcode=WSAGetLastError();  
  72.             if(errcode==WSAEWOULDBLOCK || errcode==WSAEINVAL)  //表示服务器端未准备好,继续循环  
  73.             {  
  74.                 Sleep(100);  
  75.                 continue;  
  76.             }  
  77.             else 
  78.             {  
  79.                 if(errcode == WSAEISCONN) //连接成功,则退出  
  80.                 {  
  81.                     break;   
  82.                 }  
  83.                 else                      //否则连接失败,关闭客户端套接字并释放套接字库  
  84.                 {  
  85.                     printf("connect failed!");  
  86.  
  87.                     closesocket(sClient);   
  88.                     WSACleanup(); //  
  89.                     return -1;  
  90.                 }  
  91.              }  
  92.         }  
  93.  
  94.     }  
  95.  
  96.     //发送数据  
  97.     while(true)  
  98.     {  
  99.         //  
  100.         //scanf(buf);  
  101.         //cin>>buf;  
  102.  
  103.         strcpy(buf,"Hello TCP!");  
  104.  
  105.         retVal=send(sClient,buf,strlen(buf),0); //a.回显接收数据;b.第四个参数:0?  
  106.         if(retVal == SOCKET_ERROR)  //错误处理  
  107.         {  
  108.             int errcode=WSAGetLastError();  
  109.             if(errcode == WSAEWOULDBLOCK)  //  
  110.             {  
  111.                 Sleep(100);  
  112.                 continue;  
  113.             }  
  114.             else 
  115.             {  
  116.                 printf("send failed!");  
  117.  
  118.                 closesocket(sClient);  
  119.                 //closesocket(sServer);  
  120.                 WSACleanup();  
  121.                 return -1;  
  122.  
  123.             }  
  124.         }  
  125.  
  126.         break//如果发送数据成功,则退出循环  
  127.     }  
  128.  
  129.     //接收数据  
  130.     while(true)  
  131.     {  
  132.         retVal=recv(sClient,buf,strlen(buf),0);  
  133.         if(retVal == SOCKET_ERROR)  
  134.         {  
  135.             int errcode=WSAGetLastError(); //这个变量errcode没有重复定义吗?  
  136.             if(errcode == WSAEWOULDBLOCK)  //  
  137.             {  
  138.                 Sleep(100);  
  139.                 continue;  
  140.             }  
  141.             else 
  142.             {  
  143.                 if(errcode==WSAETIMEDOUT || errcode==WSAENETDOWN)  
  144.                 {  
  145.                     printf("recv failed!");  
  146.  
  147.                     closesocket(sClient);  
  148.                     //closesocket(sServer);  
  149.                     WSACleanup();  
  150.                     return -1;  
  151.                 }  
  152.             }  
  153.         }  
  154.  
  155.         break;  
  156.     }  

 

1.

#include <winsock2.h>             //winsock.h (2种套接字版本)
#pragma comment(lib,"ws2_32.lib") //wsock32.lib

2.

retVal=ioctlsocket(sServer,FIONBIO,(u_long *)&imode); //第3个参数通常设为1(同时第2个参数设为FIONBIO),表示非阻塞模式

3.

a. //绑定套接字并将其设置为监听状态
 SOCKADDR_IN addrServ;
 addrServ.sin_family=AF_INET;
 addrServ.sin_port  =htons(5000);
 addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102");

 retVal=bind(sServer,(SOCKADDR *)&addrServ,sizeof(addrServ)); //绑定套接字到某一个具体的服务器

这一段代码表明,bind函数需要定义一个addrServ,并且要为每个字段赋值。

b. retVal=listen(sServer,1); //第二个参数,表示最大连接数目

4.

//接受连接
 sockaddr_in addrClient; //定义一个临时地址,用于接受连接(注意:某个客户端由Client.cpp确定)
 int len=sizeof(sockaddr_in);

 SOCKET sClient;
 int errcode;

 while(true)
 {
  sClient=accept(sServer,(sockaddr *)&addrClient,&len);
  if(sClient == INVALID_SOCKET)
  {
   errcode=WSAGetLastError();
   if(errcode == WSAEWOULDBLOCK)  //表示没有客户端发起连接,继续循环
   {

……

5.

retVal=recv(sClient,buf,strlen(buf),0);//第4个参数,表示影响该函数的行为(通常设为0)

retVal=send(sClient,buf,strlen(buf),0); //a.回显接收数据;b.第四个参数:0?

------------------------------------------------------------------------------------------------

1.

addrServ.sin_port  =htons(5000); //为什么要使用htons宏?前者的字段类型和宏的返回值类型一致
 addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102"); //同理,后者函数的返回值类型和字段类型一致

2.
  //scanf(buf); //问题①:为何这两个发送字符串我发送不了?
  //cin>>buf;

  strcpy(buf,"Hello TCP!"); //发送固定字符串

3.

问题②:下次继续做实验,bind failed的原因,而且是Client.cpp端出现的 真奇怪?(自己有调试,结果发现port字段和自己设置的不一致,不知为何)

你可能感兴趣的:(comment)