非阻塞模式(ioctlsocket)

时间:2021-08-27 08:07:25
     //Server.cpp
#include <stdio.h>
#include <winsock2.h> //winsock.h (2种套接字版本)
#pragma comment(lib,"ws2_32.lib") //wsock32.lib #define MAXSIZE 100 // int main()
{
//
int retVal; char buf[MAXSIZE]; //初始化套接字库
WORD wVersionRequest;
WSADATA wsadata; wVersionRequest=MAKEWORD(,); retVal=WSAStartup(wVersionRequest,&wsadata);
if(retVal == SOCKET_ERROR)
{
printf("WSAStartup failed!"); return -;
} //创建套接字
SOCKET sServer;
sServer=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sServer == INVALID_SOCKET)
{
printf("socket failed!"); WSACleanup();
return -; //每次检测到失败后,即需要返回
} //设置为非阻塞模式
int imode=;
retVal=ioctlsocket(sServer,FIONBIO,(u_long *)&imode);
if(retVal == SOCKET_ERROR)
{
printf("ioctlsocket failed!"); closesocket(sServer);
WSACleanup();
return -;
} //绑定套接字并将其设置为监听状态
SOCKADDR_IN addrServ;
addrServ.sin_family=AF_INET;
addrServ.sin_port =htons();
addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102"); retVal=bind(sServer,(SOCKADDR *)&addrServ,sizeof(addrServ)); //绑定套接字到某一个具体的服务器
if(retVal == SOCKET_ERROR)
{
printf("bind failed!"); closesocket(sServer);
WSACleanup();
return -;
} retVal=listen(sServer,); //第二个参数,表示最大连接数目
if(retVal == SOCKET_ERROR)
{
printf("listen failed!"); closesocket(sServer);
WSACleanup();
return -;
} //接受连接
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) //表示没有客户端发起连接,继续循环
{
Sleep();
continue;
}
else
{
printf("accept failed!"); closesocket(sServer); //连接失败,关闭服务器套接字并释放套接字库
WSACleanup(); //
return -;
}
} break; //
} //接收数据
while(true)
{
retVal=recv(sClient,buf,strlen(buf),);
if(retVal == SOCKET_ERROR)
{
errcode=WSAGetLastError(); //这个变量errcode没有重复定义吗?
if(errcode == WSAEWOULDBLOCK) //
{
Sleep();
continue;
}
else
{
if(errcode==WSAETIMEDOUT || errcode==WSAENETDOWN)
{
closesocket(sClient);
closesocket(sServer);
WSACleanup();
return -;
}
}
} if(buf == "quit") //如果接收数据为"quit",则发送回显"quit"
{
retVal=send(sClient,buf,strlen(buf),);
break;
}
else
{
//发送数据
while(true)
{
retVal=send(sClient,buf,strlen(buf),); //a.回显接收数据;b.第四个参数:0?
if(retVal == SOCKET_ERROR) //错误处理
{
errcode=WSAGetLastError();
if(errcode == WSAEWOULDBLOCK) //
{
Sleep();
continue;
}
else
{
closesocket(sClient);
closesocket(sServer);
WSACleanup();
return -; }
} break; //如果发送数据成功,则退出循环
} }
} }
     //Client.cpp
#include <stdio.h>
#include <WinSock2.h> //winsock.h
#pragma comment(lib,"ws2_32.lib"); //wsock32.lib #include <iostream>
using namespace std; #include <string.h> //strcpy函数 #define MAXSIZE 100 // int main()
{
//
int retVal; char buf[MAXSIZE]; //初始化套接字库
WORD wVersionRequest;
WSADATA wsadata; wVersionRequest=MAKEWORD(,); retVal=WSAStartup(wVersionRequest,&wsadata);
if(retVal == SOCKET_ERROR)
{
printf("WSAStartup failed!"); return -;
} //创建套接字
SOCKET sClient;
sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sClient == INVALID_SOCKET)
{
printf("socket failed!"); WSACleanup();
return -; //每次检测到失败后,即需要返回
} //设置为非阻塞模式
int imode=;
retVal=ioctlsocket(sClient,FIONBIO,(u_long *)&imode);
if(retVal == SOCKET_ERROR)
{
printf("ioctlsocket failed!"); closesocket(sClient);
WSACleanup();
return -;
} //发起连接
sockaddr_in addrServ;
addrServ.sin_family=AF_INET; //表示使用的是,TCP/IP地址家族
addrServ.sin_port =htons(); //为什么要使用htons宏?
addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102"); int len=sizeof(sockaddr_in); //sizeof只是一个运算符,不是函数 while(true)
{
retVal=connect(sClient,(sockaddr *)&addrServ,len); //连接到某一个具体的服务器
if(retVal == INVALID_SOCKET)
{
int errcode=WSAGetLastError();
if(errcode==WSAEWOULDBLOCK || errcode==WSAEINVAL) //表示服务器端未准备好,继续循环
{
Sleep();
continue;
}
else
{
if(errcode == WSAEISCONN) //连接成功,则退出
{
break;
}
else //否则连接失败,关闭客户端套接字并释放套接字库
{
printf("connect failed!"); closesocket(sClient);
WSACleanup(); //
return -;
}
}
} } //发送数据
while(true)
{
//
//scanf(buf);
//cin>>buf; strcpy(buf,"Hello TCP!"); retVal=send(sClient,buf,strlen(buf),); //a.回显接收数据;b.第四个参数:0?
if(retVal == SOCKET_ERROR) //错误处理
{
int errcode=WSAGetLastError();
if(errcode == WSAEWOULDBLOCK) //
{
Sleep();
continue;
}
else
{
printf("send failed!"); closesocket(sClient);
//closesocket(sServer);
WSACleanup();
return -; }
} break; //如果发送数据成功,则退出循环
} //接收数据
while(true)
{
retVal=recv(sClient,buf,strlen(buf),);
if(retVal == SOCKET_ERROR)
{
int errcode=WSAGetLastError(); //这个变量errcode没有重复定义吗?
if(errcode == WSAEWOULDBLOCK) //
{
Sleep();
continue;
}
else
{
if(errcode==WSAETIMEDOUT || errcode==WSAENETDOWN)
{
printf("recv failed!"); closesocket(sClient);
//closesocket(sServer);
WSACleanup();
return -;
}
}
} break;
}
}

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