一,區別
什麼是阻塞式
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;
}