zoukankan      html  css  js  c++  java
  • 网络编程基础第五讲非阻塞模型

                     网络编程基础第五讲非阻塞模型

    一丶简介

        通过上一讲.我们了解到了阻塞模式. recv/send IO操作不完成.不会进行返回.迭代模式就是只服务一个连接.对这个连接进行读写.

        非阻塞模式就是 IO没有完成.可以立即进行返回.

        我们可以通过方法  ioctlsocket进行设置为非阻塞

    例子:

      

    int iMode = 1; //为1表示非阻塞. 为0 表示阻塞.
    
    int nRet = ioctlsocket(SOCKET, FIONBIO,(u_long *)&iMode);

    示例代码:

      

    #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()
    ");
    
    //-------------------------
    // 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(): %ld
    ", 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: %ld
    ", iResult);
      
    
    }

    二丶完整代码解析

      非阻塞模式就是直接数据返回. 所以我们跟阻塞是的代码不一样的地方就是判断返回值. 因为返回值是立即返回.所以要判断数据是否接受到.连接是否接受到.这个是最大的区别.

    // 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()
    ");
    
            //-------------------------
            // 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(): %ld
    ", WSAGetLastError());
                WSACleanup();
                return 0;
            }
    
            //设置套接字为非阻塞模式
            iResult = ioctlsocket(m_socket, FIONBIO, &iMode);
            if (iResult != NO_ERROR)
                printf("ioctlsocket failed with error: %ld
    ", 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("延迟连接出错
    ");
                        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("网络中断.或者接受数据超时
    ");
                        closesocket(hClientSocket);
                        closesocket(m_socket);
                        WSACleanup();
                        break;
                    }
    
                }   
                //成功接受.打印出来.
                szRecvBuffer[0x1000] = ''; //加个结尾.
                printf(szRecvBuffer);
            }
        return -1;
    }

      

  • 相关阅读:
    CodeForces 19D Points (线段树+set)
    FZU 2105 Digits Count
    HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
    HDU 5634 Rikka with Phi (线段树)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
  • 原文地址:https://www.cnblogs.com/iBinary/p/9682217.html
Copyright © 2011-2022 走看看