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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章