zoukankan      html  css  js  c++  java
  • 网络编程IO模型学习笔记

    网络编程IO模型:

    1.主要的4种IO模型:

    ①阻塞IO:最常用,简单,效率最低

    ②非阻塞IO:可防止进程阻塞在IO操作上,需要轮询。。。

    ③IO多路复用:允许同时对多个IO进行控制。

    ④信号驱动IO:

    2.阻塞IO:

    --read函数:----阻塞,需要内核去唤醒该进程。。。。

    --write阻塞:主要发生的情况??

    用户缓冲区:???数组。。

    UDP无发送缓存区,写操作sendto永远都不会阻塞。()

    3.非阻塞IO------使用比较少,了解有这种模式

    --缓冲区满,不阻塞,它返回一个错误编号

    --例如 waitpid(-1,&a, WHOHANG )

    --例如 fifo  open()参数中加入非阻塞参数

    fnctlfd cmd arg)函数:改变一个描述符的属性,设置为O_NONBLOCK来实现非阻塞。

    --cmd:命令  F_GETFL获得属性,并存放到flag中,arg忽略,传入0即可;F_SETFL设置属性

    --arg:  

    4.多路复用IO:(重点)

    --一个进程处理多个人进程。。。。

    --基本思想:先构造一张有关描述符的表fd_set  rdfs,然后调用select函数。

    ①fd_set  类似申明了一个一维数组  int  rdfs[256];

    ②FD_ZERO 作用相当于数组清零-----00000000000000

    ③FD_SET(0, &rdfs) 将文件描述符为0的地方(套接字缓存区),置一

      FD_SET (LIStenfd,&rdfs)

    ③如果select 返回值大于0;则遍历数组

    for (i= 0; i < ; i++)

    {

             if (FD_ISSET(i, &rdfs)>0)

    {

             if (i==0) fgets。。。。

             if (i== listenfd)

    accept。。。。

    }

    }

    select函数特点:

    ①     返回 n = select函数(,,,,, 0)就绪的描述符的个数。。

    ②它把没就绪的位清0.   使用FD_ISSET函数遍历数组,为0的位置调用accept函数

    ③作用查看缓冲区状态:

    服务器模型:

    1循环服务器

    ―――TCP服务器

    ―――UDP服务器

    2.并发服务器

    *********IO多路复用并发服务器*********

    初始化(socket---bind---listen)

    ①fd_set  类似申明了一个一维数组  int  rdfs[256];

    ②FD_ZERO 作用相当于数组清零-----00000000000000

    ②     FD_SET(0, &rdfs) 将文件描述符为0的地方(套接字缓存区),置一

      FD_SET (LIStenfd,&rdfs)

    fd_set  f1,f2;

    FD_ZERO(&f1)

    FD_SET( ,&f1)

    while(1)

    {

             f2 = f1;

             if (select(。。。f2.。。。。)>0)

             {       

                       for (i= 0; i <= maxfd; i++)

    {

                                if (FD_ISSET(i, &f2)>0)

    {

                                if (i== listenfd)

    connfd = accept();

                                         FD_SET(f1);

                                }

                                else

                                {

                                         recv(…….);

    }                          

    }

    }

    }

    TCP并发服务器:

    while(1){

                       connfd = accept(。。。);

                       fork()

                       if (pid == 0) -------

    close(listenfd);

    while (1)

    {

             。。。。。。

    }

    exit(0);//发送结束信号,异步方式解决僵尸问题

             else------父进程

                close(connfd);

    }

    void  SignalHander(int  signo)异步方式解决僵尸问题

    {

             while(waitpid(-1, NULL, WHOHANG)>0);

    }

    网络属性设置:

    getsockopt()

    setsockopt(sockfd, level, optname, *optval, socklen_t)

    level: SOL_SOCKET

    optname:  SO_BROADCAST

    optval: 存放选项值的缓冲区长度地址

    socklen_t: 缓冲长度

    网络超时检测:

    i.在网络通信中,很多操作都会使进程阻塞;TCP套接字中的recv/accept/connet和UDP套接字中的recvform;

    超时检测的必要性:

    i.避免进程在没有数据时无限的阻塞;ii.当设定时间到时,进程从原来的操作返回继续进行。

    三种方法检测网络超时:

    方法一:

    设置套接字属性:SO_RCVTIMEO

    struct  timeval  timev;

    timev.tv_sec = 5;

    timev.tv_usec = 0;

    …….

    setsocketopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &TIMEV, sizeof(timev)); //设置接收超时

    ………

    recv()/recvfrom…..//从套接字读取数据。。。

    方法二:

    用select检测socket是否准备就绪;

    struct  fd_set  rdfs;

    struct  timeval  tv = {5, 0}; // 设置5秒时间

    FD_ZERO(&rdfs);

    FD_SET(sockfd, &rdfs);

    if (select (sockfd, &rdfs,NULL,NULL,NULL,&tv) > 0) // sockfd就绪

    {

             recv()/recvfrom()// 从socket中读取数据

    }

    方法三:

    设置定时器timer,捕捉SIGALRM信号

    void  hander(int  signo){ return ;}

    struct  sigaction  act;

    sigaction(SIGALRM, NULL,&act);

    act.sa_hander  =  hander();

    act.sa_flags  &=  ~SA_RESTART; //将某位清0

    sigaction(SIGALRM, &act, NULL);

    alarm(5);

    if (recv(,,,) <0) ………

    记住一两个错误编号和宏:

    errno = 11 是连接超时

    errno = 4  是中断system call  宏:EINTR

    广播:

    1.数据包发送方式只有一个接收方,叫单播;

    2.同时发给局域网中的所有主机,称为广播;广播只能用户数据报,即UDP协议,套接字才能广播;

    3.广播地址:

    广播发送流程: 创建数据报套接字---à设置setsockopt套接字属性---à指定接收方为广播地址--à指定端口信息---à发送数据包

    sockfd = socket(; ; );

    ………..

    int  on = 1;

    setsockopt(socket,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));

    ……..

    sendto(………);

    广播的接收流程:创建数据报套接字---à绑定本机IP地址和端口---à绑定的端口必须和发送方指定的端口相同----à等待接收数据;

    注意绑定本机IP地址一般为(0.0.0.0)  端口 htonl(INADDR_ANY)

    组播:

    只用加入某个多播组的主机才能收到数据;

    网络地址:ABCD类地址

    下面是广播和组播图:

     

    组播的发送方流程:

    socket--àsendto---à选择D类地址---àsleep(1)

    组播的接收方流程:创建用户数据报套接字--à加入多播组---à绑定本机的IP地址和端口--à等待接收数据

    socket--àsetsockopt---àbind---àrecvfrom

    libcap编程:

  • 相关阅读:
    【InfoPath2007】The form has been closed
    深入浅出Nintex——调用子流程
    深入浅出Nintex——使用查询XML动作
    深入浅出Nintex——使用Call WebService来查询Item ID
    深入浅出Nintex——获得某群组的用户集合
    深入浅出SharePoint2007——Webpart开发
    深入浅出Nintex——获得指定用户的角色
    深入浅出Nintex——使用构建动态字符串动作
    Lucene.net 实现全文搜索
    DotLucene源码浅读笔记(1)补遗:编写简单中文分词器ChineseAnalyzer
  • 原文地址:https://www.cnblogs.com/zhou2011/p/2342779.html
Copyright © 2011-2022 走看看