一,区别
什么是阻塞式
1,在创建一个套接字后,默认的都是阻塞式的。
Winsocket的IO函数比如:Send和Recv,必须等待函数完成相应的I/O操作后,才能继续。
什么是非阻塞式
1,通过调用ioctisocket(SCOKET s,long cmd,u_long *arpy)函数,改变套接字的模式。
U-long nNoBlock = 1;
loctisocket(s,FLONBIO,&nNoBlock);
2,无论操作是否完成吗非阻塞式函数都会立即返回。
例如,在非阻塞模式下调用recv接收数据时,程序会直接读取网络缓冲区中的数据,无论是否读到数据,函数都会立即返回。
二,关键函数
非阻塞式套接字设定
int iMode = 1; //为1是表示非阻塞 0表示阻塞
nRet = ioctisocket(hSocket,FIONBIO,(u_long FAR*)&iMode); //第二个类型为FIONBIO表示可用
三,代码
// 非阻塞式.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#define BUF_MAXSIZE 225
#include "winsock2.h" //WinSock2的头文件winsock2.h
#pragma comment(lib, "ws2_32.lib") //导入库文件ws2_32.lib,链接WinSock导入库
#include<iostream>
using namespace std;
int main()
{
WSADATA wsaData; //指向WASDATA结构体变量的指针
WORD wVersion = MAKEWORD(2, 2); //版本号
if (WSAStartup(wVersion, &wsaData) != 0) //加载WinSock动态链接库
{
cout << "加载winsock.dll失败!\n";
return 0;
}
char Buf[BUF_MAXSIZE];
//用于创建 与指定的服务提供者进行绑定
SOCKET hSocket;
hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
{
cout << "创建套接字失败!\n";
closesocket(hSocket);
WSACleanup();
return -1;
}
//绑定(bind函数)
sockaddr_in addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(8000);
addrServer.sin_addr.s_addr = htonl(INADDR_ANY);
int nRet = bind(hSocket, (LPSOCKADDR)&addrServer, sizeof(addrServer));
if (nRet == SOCKET_ERROR) //绑定地址 套接字:sockaddr结构指针:缓冲区长度
{
printf("邦定失败!\n");
closesocket(hSocket);
WSACleanup();
return -1;
}
//监听
nRet = listen(hSocket, 10);
if (nRet == SOCKET_ERROR)
{
cout << "监听失败";
closesocket(hSocket);
WSACleanup();
return -1;
}
int iMode = 1; //为1是非阻塞,0表示阻塞
//第二个类型为FIONBIO 可用
nRet = ioctlsocket(hSocket, FIONBIO, (u_long FAR*)&iMode);
sockaddr_in saClient;
int nSaClientSize = sizeof(saClient);
SOCKET hClient;
while (true)
{
//因为是非阻塞式,所以他会直接返回
hClient = accept(hSocket, (LPSOCKADDR)&saClient, &nSaClientSize);
if (hClient == INVALID_SOCKET)
{
int nErroCode = WSAGetLastError();
if (nErroCode == WSAEWOULDBLOCK) //如果出现发送数据错误,先Sleep一段时间,在重新连接
{
Sleep(100);
continue;
}
else
{
cout << "accept Error";
closesocket(hSocket);
WSACleanup();
return - 1;
}
}
break;
}
while (true)
{
memset(Buf, 0, BUF_MAXSIZE);
nRet = recv(hClient, Buf, BUF_MAXSIZE, 0);
if (SOCKET_ERROR == nRet)
{
int nErrorCode = WSAGetLastError();
//接收数据缓冲区暂无数据
if (nErrorCode == WSAEWOULDBLOCK)
{
Sleep(100);
continue;
}
//超时和网络中断
else if (nErrorCode == WSAETIMEDOUT || nErrorCode == WSAENETDOWN)
{
cout << "recv error\n";
closesocket(hClient);
closesocket(hSocket);
WSACleanup();
return -1;
}
}
char tempChar[0x200];
sprintf_s(tempChar, "接收到一条数据:IP:[%s],信息:\"%s\"\n", inet_ntoa(saClient.sin_addr), Buf);
cout << tempChar << endl;
if (strcmp(Buf, "close") == 0)
{
nRet = send(hClient, "close", strlen("close"), 0);
break;
}
else
{
nRet = send(hClient, Buf, strlen(Buf), 0);
if (SOCKET_ERROR == nRet)
{
int nErrorCode = WSAGetLastError();
//无法立即完成阻塞套接字上的操作
if (nErrorCode == WSAEWOULDBLOCK)
{
Sleep(100);
continue;
}
//超时和网络中断
else
{
cout << "send error\n";
closesocket(hClient);
closesocket(hSocket);
WSACleanup();
return -1;
}
}
}
break;
}
closesocket(hClient);
closesocket(hSocket);
WSACleanup();
system("pause");
return 0;
}