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

      

  • 相关阅读:
    转载--gulp入门
    grunt之easy demo
    CentOS下vm虚拟机桥接联网
    Webstorm & PhpStorm
    2.使用Package Control组件安装
    virtual方法和abstract方法
    sql server 2008 跨服务器查询
    .NET开源项目常用记录
    vs2010 安装MVC 3.0
    所有运行命令指令大全
  • 原文地址:https://www.cnblogs.com/iBinary/p/9682217.html
Copyright © 2011-2022 走看看