一丶简介
通过上一讲.我们了解到了阻塞模式. recv/send IO操作不完成.不会进行返回.迭代模式就是只服务一个连接.对这个连接进行读写.
非阻塞模式就是 IO没有完成.可以立即进行返回.
我们可以通过方法 ioctlsocket进行设置为非阻塞
例子:
代码语言:javascript复制int iMode = 1; //为1表示非阻塞. 为0 表示阻塞.
int nRet = ioctlsocket(SOCKET, FIONBIO,(u_long *)&iMode);
示例代码:
代码语言:javascript复制#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
void main()
{
//-------------------------
// Initialize Winsock
WSADATA wsaData;
int iResult;
u_long iMode = 0;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
printf("Error at WSAStartup()n");
//-------------------------
// Create a SOCKET object.
SOCKET m_socket;
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET) {
printf("Error at socket(): %ldn", WSAGetLastError());
WSACleanup();
return;
}
//-------------------------
// Set the socket I/O mode: In this case FIONBIO
// enables or disables the blocking mode for the
// socket based on the numerical value of iMode.
// If iMode = 0, blocking is enabled;
// If iMode != 0, non-blocking mode is enabled.
iResult = ioctlsocket(m_socket, FIONBIO, &iMode);
if (iResult != NO_ERROR)
printf("ioctlsocket failed with error: %ldn", iResult);
}
二丶完整代码解析
非阻塞模式就是直接数据返回. 所以我们跟阻塞是的代码不一样的地方就是判断返回值. 因为返回值是立即返回.所以要判断数据是否接受到.连接是否接受到.这个是最大的区别.
代码语言:javascript复制// Server.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA wsaData;
int iResult;
u_long iMode = 0;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
printf("Error at WSAStartup()n");
//-------------------------
// Create a SOCKET object.
SOCKET m_socket;
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET) {
printf("Error at socket(): %ldn", WSAGetLastError());
WSACleanup();
return 0;
}
//设置套接字为非阻塞模式
iResult = ioctlsocket(m_socket, FIONBIO, &iMode);
if (iResult != NO_ERROR)
printf("ioctlsocket failed with error: %ldn", iResult);
//主要是进行连接的时候.代码不一样了.因为是非阻塞.所以返回的错误是资源暂时不可用.
sockaddr_in hClientAddr;
int nAddrSize = sizeof(hClientAddr);
SOCKET hClientSocket;
while (true)
{
hClientSocket = accept(m_socket,(sockaddr *) &hClientAddr, &nAddrSize);
if (INVALID_SOCKET == hClientSocket) //因为是立即返回.所以错误会是INVALID_SOCKET 所以我们要进行错误码判断.
{
int iCode = GetLastError(); //使用那个都可以
int nCode = WSAGetLastError();
if (nCode == WSAEWOULDBLOCK) //资源暂时不可用.所以延迟继续进行连接 具体查询WSALastError()关于套接字的返回错误.
{
Sleep(100);
continue;
}
else
{
printf("延迟连接出错rn");
closesocket(m_socket);
WSACleanup();
break; //否则错误.
}
}
}
//recv一样会返回.
char szRecvBuffer[0x1000] = { 0 };
while (true)
{
RtlZeroMemory(szRecvBuffer, sizeof(szRecvBuffer)); //清空缓冲区.
if (SOCKET_ERROR == recv(hClientSocket,szRecvBuffer,0x1000,0))//非阻塞一样判断
{
int iErrCode = GetLastError();
if (iErrCode == WSAEWOULDBLOCK)
{
/*
暂时无法接受.延迟继续接受.
注意这一次接受的数据我们需要保存起来.下次接受还要保存.最后判断数据是否完整.
非阻塞就是这样做的.所以具体写法自己实现
*/
Sleep(100);
continue;
}
else if (iErrCode == WSAETIMEDOUT || iErrCode == WSAENETDOWN)
{
//超时跟网络中断.打印输出并且释放资源
printf("网络中断.或者接受数据超时rn");
closesocket(hClientSocket);
closesocket(m_socket);
WSACleanup();
break;
}
}
//成功接受.打印出来.
szRecvBuffer[0x1000] = '