前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络编程基础第五讲非阻塞模型

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

作者头像
IBinary
发布2019-05-25 16:46:48
4890
发布2019-05-25 16:46:48
举报
文章被收录于专栏:逆向技术逆向技术

一丶简介

    通过上一讲.我们了解到了阻塞模式. 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(): %ld\n", 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\n", 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(): %ld\n", WSAGetLastError());
            WSACleanup();
            return 0;
        }

        //设置套接字为非阻塞模式
        iResult = ioctlsocket(m_socket, FIONBIO, &iMode);
        if (iResult != NO_ERROR)
            printf("ioctlsocket failed with error: %ld\n", 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("延迟连接出错\r\n");
                    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("网络中断.或者接受数据超时\r\n");
                    closesocket(hClientSocket);
                    closesocket(m_socket);
                    WSACleanup();
                    break;
                }

            }   
            //成功接受.打印出来.
            szRecvBuffer[0x1000] = '\0'; //加个结尾.
            printf(szRecvBuffer);
        }
    return -1;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-09-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一丶简介
  • 二丶完整代码解析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档