Windows网络编程 非阻塞式

一,区别

什么是阻塞式

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;
}

猜你喜欢

转载自blog.csdn.net/qq_46423166/article/details/106094758