zoukankan      html  css  js  c++  java
  • UNP学习 广播

    一、概述

    虽然UDP支持各种形式的地址,但TCP只支持单播地址。

    上图要点是:

    • IPv4对多播的支持是可选的,而IPv6则时必须的。
    • IPv6没有提供对广播的支持:当使用广播的IPv4应用程序一直到IPv6时,必须使用IPv6的多播方式进行重新编码。
    • 广播和多播要使用UDP,二者都不能使用TCP

    广播的用途:

    1.假定服务器主机在本地子网上,但不知道它的单播IP地址时,对它进行定位,这就是资源发现。

    2.当有多个客户和单个服务器通信时,减少局域网上数据流量。

    常见的实例

    1.ARP:ARP是IPv4的一个i额基本组成部分,而不是一个用户应用程序。

    2.BOOTP(引导协议,Bootstrap Protocol):客户假定有一台服务器主机在本地子网上。

    3.NTP(网络时间协议,Network Timer Protocol):一种常见的情形是:一个NTP客户主机可能配置成使用一个或多个服务器主机IP地址,其上面的NTP客户于是以某个频率轮询这些服务器。

    4.路由后台进程。

    二、广播地址

    如果用{netid,subnetid,hostid}({网络ID,子网ID,主机ID})表示IPv4地址,那么有四种类型的广播地址。

    1.子网广播地址:{netid,subnetid,-1}。这类地址编排指定子网上的所有接口。

    2.全部子网广播地址:{netid,-1,-1}。这类广播地址编排指定网络上的所有子网。

    3.网络广播地址:{netid,-1}。这类地址用于不进行子网划分的网络。

    4.受限广播地址:{-1,-1,-1}或255.255.255.255。路由器从不转发目的地址为255.255.255.255的IP数据报

    三、竞争状态

      多个进程访问共享数据,但正确结果依赖于进程的执行顺序,这种情况我们称之为竞争状态。

    竞争状态通常是线程编程中时钟要注意的一个重要问题,因为在线程中有非常多的数据需要共享。

       在进行信号处理时,通常会出现各种类型的竞争状态。这是因为在我们的程序执行过程中,内核随时都会递交信号。

    例子1:

     1 #include "unp.h"
     2 static void recvfrom_alarm(int);
     3 void
     4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
     5 {
     6     int n;
     7     const int on = 1;
     8     char sendline[MAXLINE], recvline[MAXLINE+1];
     9     sigset_t sigset_alarm;
    10     socklen_t len;
    11     struct sockaddr *preply_addr;
    12     preply_addr = Malloc(servlen);
    13     Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
    14     Sigemptyset(&sigset_alarm);
    15     Signal(SIGALRM, recvfrom_alarm);
    16     while(Fgets(sendline, MAXLINE, fp) != NULL) {
    17         Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
    18         alarm(5);
    19         for( ; ;) {
    20             len = servlen;
    21             Sigprocmask(SIG_UNBLOCK, &sigset_alrm, NULL);
    22             n = recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);
    23             Sigprocmask(SIG_BLOCK, &sigset_alrm, NULL);
    24             if(n < 0) {
    25                 if(errno == EINTR)
    26                     break;              /* waited long enough for replies */
    27                 else
    28                     err_sys("recvfrom error");
    29             } else {
    30                 recvline[n] = 0;        /* null terminate */
    31                 printf("from %s: %s", Sock_ntop_host(preply_addr, len), recvline);
    32             }
    33         }
    34     }
    35 }
    36 
    37 static void 
    38 recvfrom_alarm(int signo)
    39 {
    40     return;     /* just nterrupt the recvfrom() */
    41 }
    example1

    解阻塞信号、调用recvfrom和阻塞信号都是互相独立的系统调用。假定recvfrom返回了最后一个应答数据报并且SIGALRM信号在recvfrom和阻塞信号之间递交,下一次recvfrom的调用将永远阻塞。错误

    例子2:

    #include "unp.h"
    #include <setjmp.h>
    static void recvfrom_alarm(int);
    static sigjmp_buf jmpbuf;
    void
    dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
    {
        int n;
        const int on = 1;
        char sendline[MAXLINE], recvline[MAXLINE+1];
        socklen_t len;
        struct sockaddr *preply_addr;
        preply_addr = Malloc(servlen);
        Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
        Signal(SIGALRM, recvfrom_alarm);
        while(Fgets(sendline, MAXLINE, fp) != NULL) {
            Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
            alarm(5);
            for( ; ; ) {
                if(sigsetjmp(jmpbuf, 1) != 0)
                    break;
                len = servlen;
                n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);
                recvline[n] = 0;
                printf("from %s: %s", Sock_ntop_host(preply_addr, len), recvline);
            }
        }
    }
    static void
    recvfrom_alarm(int signo)
    {
        siglongjmp(jmpbuf, 1);
    }
    example2

     pselect的关键点是设置信号掩码、测试描述字及恢复信号掩码等操作都是原子操作。错误

    例子3:

    #include "unp.h"
    static void recvfrom_alarm(int);
    static int pipefd[2];
    void
    dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
    {
        int n, maxfdp1;
        const int on = 1;
        char sendline[MAXLINE], recvline[MAXLINE + 1];
        fd_set rset;
        socklen_t len;
        struct sockaddr *preply_addr;
        preply_addr = Malloc(servlen);
        Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
        Pipe(pipefd);
        maxfdp1 = max(sockfd, pipefd[0]) + 1;
        FD_ZERO(&rset);
        Signal(SIGALRM, recvfrom_alarm);
        while(Fgets(sendline, MAXLINE, fp) != NULL) {
            Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
            alarm(5);
            for( ; ; ) {
                FD_SET(sockfd, &rset);
                FD_SET(pipefd[0], &rset);
                if((n = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
                    if(errno == EINTR)
                        continue;
                    else
                        err_sys("select error");
                }
                if(FD_ISSET(sockfd, &rset)) {
                    len = servlen;
                    n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);
                    recvline[n] = 0;
                    printf("from %s: %s", Sock_ntop_host(preply_addr, len), recvline);
                }
                if(FD_ISSET(pipefd[0], &rset)) {
                    Read(pipefd[0], &n, 1);
                    break;
                }
            }
        }
    }
    static void
    recvfrom_alarm(int signo)
    {
        Write(pipefd[1], "", 1);
        return;
    }
    example3

     另一个解决同一问题的正确方法。不是让信号处理简单的返回,期望这样能够中断被阻塞的rrecvfrom相反,我们让信号黑醋栗程序使用IPC通知dg_cli函数到抵制其到时。

    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    数据库的左右表连接
    数据库索引-索引的优点、缺点、分类、不走索引的情况
    selenium中日期控件的操作方法
    esdoc 自动生成接口文档介绍
    css设置背景图(背景图太大导致图片显示不全)
    k8s调度器及调度队列源码分析
    MIT6.824 2020 Lab1 MapReduce 实现
    git命令
    python3.6、3.9多版本安装共存
    使用蓝鲸平台登录态验证接入第三方系统
  • 原文地址:https://www.cnblogs.com/ch122633/p/8590894.html
Copyright © 2011-2022 走看看