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

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

    一丶阻塞模型简介

      不知道大家有没有注意到.我们客户端 或者服务端.的TCP 收发数据的时候(send/recv)如果接受不到数据就一直不返回.从而造成我们网络的阻塞.程序无法正常执行.

    不过针对这一方法.我们可以开一个线程去专门接受数据.或者发送数据.

    这个就是我们常说的阻塞.

    只要我们创建的套接字都是阻塞模型. 就是说数据接受不到不返回.

    我们可以设置为非阻塞.就是不管数据有没有来到都会返回.如果来到.会有通知.我们可以编程接受数据.

    设置非阻塞模式方法

      ioctlsocket(SOCKET s, long cmd, u_long *arpg);

    改变套接字模式.为飞租she.

    二丶阻塞模式迭代模式 与 并发连接模式

      1.阻塞模式的迭代模式 就是指每次只服务一个连接.只有服务完当前的客户端连接之后.才会继续服务下一个客户连接

      2.并发连接模式 通过多线程.可以同时服务多个链接.没一个线程处理一个客户端的连接.

    阻塞迭代模式步骤

      1.生成一个函数.绑定本地地址跟监听.

      2.生成一个函数.专门接受一个客户端连接.并且返回对应连接的套接字.

      3.处理没一个客户端的连接.实现接受跟发送数据.

      4.关闭一个连接.

    其实就是讲创建服务端网络做了一个封装.

    如下代码. 一个.h文件.存放函数声明.一个.cpp封装了网络连接的代码.

    .h文件:

    #pragma once
    #include "stdafx.h"
    #include <WinSock2.h>
    #include <iostream>
    #pragma comment(lib,"ws2_32.lib")
    using namespace std;
    
    
    #include "initSocket.h"
    
    void DebugLog(TCHAR *str);
    //初始化数据
    int initSocket();
    
    //1.创建套接字.绑定地址,开始监听
    SOCKET BindAnListen(int nBacklog);
    
    //接受连接分装
    
    SOCKET AccepeConnect(SOCKET hSocket);
    
    //接受跟发送数据
    BOOL ClientReadAnWriteData(SOCKET hSocket);
    
    //关闭数据连接
    BOOL ColseConnect(SOCKET hSocket);

    .cpp实现.

    #include "initSocket.h"
    
    void DebugLog(TCHAR *str)
    {
        cout << str << WSAGetLastError() << endl;
    }
    //初始化数据
    int initSocket()
    {
        WSADATA data;
        if (WSAStartup(MAKEWORD(2, 2), &data))
        {
            DebugLog(TEXT("initsocket faile"));
            return 0;
        }
    }
    
    //1.创建套接字.绑定地址,开始监听
    SOCKET BindAnListen(int nBacklog)
    {
        //创建套接字
        BOOL bRet = FALSE;
        SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (INVALID_SOCKET == hSocket)
        {
            DebugLog(TEXT("BindAnListen Fail"));
            return INVALID_SOCKET;
        }
                    
        //绑定套接字
        sockaddr_in addr;
        addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        //htonl addr_any
        addr.sin_family = AF_INET;
        addr.sin_port = htons(8524);
        bRet =  bind(hSocket, (sockaddr *)&addr, sizeof(addr));
        if (SOCKET_ERROR == bRet)
        {
    
            DebugLog(TEXT("bind fail"));
            closesocket(hSocket);
            WSACleanup();
            return INVALID_SOCKET;
        }
        //监听套接字
        bRet = FALSE;
        bRet =  listen(hSocket, nBacklog);
        if (SOCKET_ERROR ==bRet)
        {
            DebugLog(TEXT("Listen fail"));
            closesocket(hSocket);
            WSACleanup();
            return INVALID_SOCKET;
        }
        return hSocket;
    }
    
    //接受连接分装
    
    SOCKET AccepeConnect(SOCKET hSocket)
    {
        sockaddr_in addr;
        int nSize = sizeof(addr);
        SOCKET hNewSocket = accept(hSocket, (LPSOCKADDR)&addr, &nSize);
        if (hNewSocket == INVALID_SOCKET)
        {
    
            DebugLog(TEXT("Accept An Connect Fail"));
            return INVALID_SOCKET;
        }
        return hNewSocket;
    }
    
    //接受跟发送数据
    BOOL ClientReadAnWriteData(SOCKET hSocket)
    {
        char szBuffer[1024] = { NULL };
        int nBufferSzie = sizeof(szBuffer);
        //循环处理数据
        int nRecvBytes = 0;
        do
        {
            nRecvBytes = recv(hSocket,szBuffer, nBufferSzie, 0);
            if (SOCKET_ERROR == nRecvBytes)
            {
    
                DebugLog(TEXT("Recv Data Fail"));
                return FALSE;
            }
            else if (0 != nRecvBytes)
            {
           szBuffer[nRecvBytes] = 0;      cout
    << "接受到的数据为: " << szBuffer << endl; //接着循环发送回去. int nSendDataBytes = 0; while (nSendDataBytes < nRecvBytes) { int nRetValue = send(hSocket, szBuffer, nBufferSzie, 0); if (nRetValue > 0) { nSendDataBytes = nSendDataBytes + nRetValue; //每次发送的数据都增加.这样就会发送过去了 } else if (nRetValue == SOCKET_ERROR) { DebugLog(TEXT("发送数据失败")); return FALSE; } else { //send 返回0 也就是send失败了.客户端关闭了 DebugLog(TEXT("发送数据失败,客户端已经关闭了")); return FALSE; } } } } while (0 != nRecvBytes); return FALSE; } BOOL ColseConnect(SOCKET hSocket) { //shutdown 跟 closesocket一样.不过 TCP 会发送一个FIN分段.给对方表名已经完成数据发送 if (shutdown(hSocket,SD_SEND) == SOCKET_ERROR) { DebugLog(TEXT("关闭连接失败")); return FALSE; } //注意.客户端会发送一个数据.不写也可以. return TRUE; }

    上面的代码只是把我们网络创建的一些步骤给封装了.并没有实际编写我们用的代码.

    在main函数中使用.只服务一个socket操作

    // Server.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "initSocket.h"
    
    
    int main()
    {
        //初始化
        initSocket();
        //1.绑定并且监听
        SOCKET hSocket = BindAnListen(1);
        if (INVALID_SOCKET == hSocket)
        {
            DebugLog(TEXT("main Bind Fail"));
            goto Opt;
        }
        // 2.循环接受套接字连接
        while (true)                            //主要代码是这里.
        {
            //接受客户端连接
            SOCKET hRetSocket = AccepeConnect(hSocket);
    
            if (INVALID_SOCKET == hRetSocket)
            {
                DebugLog(TEXT("main accept Fail"));
                break;
            }
            
            //读取数据.
            if (FALSE == ClientReadAnWriteData(hRetSocket))
            {
                //只服务一个socket.对其进行读取写入操作.然后下方进行关闭.
    
                break;
            }
            if (ColseConnect(hRetSocket))
            {
                break;
            }
    
        }
    
    Opt:
        getchar(); //等待一下.观看错误内容
        ColseConnect(hSocket);
    
        return 0;
    }

    主要就是服务端的代码.客户端进行发送数据即可.

     链接:https://pan.baidu.com/s/1_vdcmPE0cYaFPn9LG5U9ug 密码:8ezo

  • 相关阅读:
    函数总结
    python之内置函数,匿名函数
    列表推导式 生成器表达式
    迭代器和生成器函数
    最近练习题
    python----------闭包 、装饰器
    python的逻辑运算符
    python------函数嵌套及作用域链
    python ---------函数
    如何实现负载均衡
  • 原文地址:https://www.cnblogs.com/iBinary/p/9676437.html
Copyright © 2011-2022 走看看