非阻塞模式(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 169 }
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 } 157 }
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字段和自己设置的不一致,不知为何)
http://qxzbgzh.blog.51cto.com/blog/2821013/875991