• linux学习之多高并发服务器篇(三)


    UDP多播服务器

    多播

      组播组可以是永久的也可以是临时的。组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发 生变化。永久组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久组播组使用的ip组播地址,可以被临时组播组利用。 

    224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;  
    224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;  224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;   
    239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。

    ip ad

    查看网卡编号

    if_nametoindex

       将几台电脑分为一个组,同一个组内本身每个电脑都有自己的ip地址,同组的都有一个组号,若想把一个包发给一个组,目的ip设为组号。一对多的数据传输,在ip层存在一个组播的概念,客户端的ip地址没有意义了,客户端要接受的端口号仍然有意义,tcp或udp封装端口号,说明哪个进程接受,一般应用于UDP领域,TCP用的非常少。

       若server要发一个组播包,write(sockfd,buf,buflen);引入一个新的函数setsockopt,可以设置多层协议。

    实例:

    复制代码
    /* server.c */
    
    #include <stdio.h>
    #include <string.h>
    #include <netinet/in.h>
    #include<net/if.h>
    #include "wrap.h"
    #define MAXLINE 80
    #define SERV_PORT 8000
    #define CLIENT_PORT 9000//客户端的端口号
    #define GROUP "239.0.0.2"
    
    int main(void)
    {
        struct sockaddr_in servaddr, cliaddr;//用于IPv4的地址
        socklen_t cliaddr_len;
        int sockfd;//文件描述符
        char buf[MAXLINE];
        char str[INET_ADDRSTRLEN];//16 Bytes
        struct ip_mreqn group;
        ssize_t len;
        int i, n;
        /*构造用于UDP通信的套接字*/
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);//
    
        bzero(&servaddr, sizeof(servaddr));//将地址清零
        //设置地址
        servaddr.sin_family = AF_INET;/*IPv4*/
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//网络字节数,本地任意IP
        servaddr.sin_port = htons(SERV_PORT);
    
        bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
        
        /*设置组地址*/
        inet_pton(AF_INET,GROUP,&group.imr_multiaddr);
        /*本地任意IP*/
        inet_pton(AF_INET,"0.0.0.0",&group.imr_address);
        /*eth0-->编号 命令:ip ad*/
        group.imr_ifindex=if_nametoindex("eth0");
    
        setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_IF,&group,sizeof(group));
    
       /*构造client 地址 IP+端口*/ 
        bzero(&clientaddr, sizeof(clientaddr));//将地址清零 //设置地址
      clientaddr.sin_family = AF_INET;/*IPv4*/
      inet_pton(AF_INET,GROUP,&clientaddr.sin_addr.s_addr);
      clientaddr.sin_port=htons(CLIENT_PORT);
      printf("Accepting connections ...
    "); 
    
      while (1) 
          {   
        fgets(buf,sizeof(buf),stdin); 
        sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&clientaddr,sizeof(clinetaddr));
         } 
      close(sockfd);
       return 0; 
    } 
    复制代码
    复制代码
    /* client.c */
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include<net/if.h>
    #include <netinet/in.h>
    #include "wrap.h"
    #define MAXLINE 4096
    #define SERVER_PORT 8000
    #define CLIENT_PORT 9000
    #define GROUP "239.0.0.2”
    int main(int argc, char *argv[])
    {
              struct sockaddr_in serveraddr,localaddr;
              int confd;
              ssize_t len;
              struck ip_mreqn   group;//组播结构体
              char buf[MAXLINE];
    
              //1.创建一个socket
              confd=socket(AF_INET,SOCK_DGRAM,0);
             
             //2.初始化本地端地址
             bzero(&localaddr,sizeof(localaddr));
             localaddr.sin_family=AF_INET;
             inet_pton(AF_INET,"0.0.0.0",&localaddr.sin_addr.s_addr);
             localaddr.sin_port=htons(CLIENT_PORT);
             bind(confd,(struct sockaddr *)&localaddr,sizeof(localaddr));
             
    
              //加入多播组
              inet_pton(AF_INET,GROUP,&group.imr_multiaddr);
              inet_pton(AF_INET,"0.0.0.0",&group.imr_address);
              group.imr_ifindex=if_nametoindex("eth0");
              
             //设置client加入多播组
              setsockopt(confd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group));
    
            while(1)
            {
                     len=recvfrom(confd,buf,sizeof(buf),0,NULL,0);
                     write(STDOUT_FILENO,buf,len);
             }
             close(confd);
             return 0;
              
    }  
    复制代码

    其他常用函数

    名字与地址转换:

    复制代码
    过时,仅用于IPv4,线程不安全
    
    gethostbyname  通过网址知道ip地址
    
    gethostbyaddr    通过IP地址知道网址
    
    
    
    getservbyname
    getservbyport
    
    根据服务器程序名字或端口号获取信息,用的不多
    
    
    
    getaddrinfo
    getnameinfo
    
    freeaddrinfo   
    
    趋势,可同时处理IPv4和IPv6,线程安全
    复制代码

    套接口和地址关联

    复制代码
    getsockname
    
    根据accept返回的的sockfd,得到临时端口号
    
    getpeername
    
    根据accept返回的sockfd,得到远端链接的端口号,在exec后可以获取客户端信息
    复制代码
    来源https://www.cnblogs.com/rainbow1122/p/7891490.html
  • 相关阅读:
    【题解】SCOI2007组队
    【题解】Atcoder AGC#16 E-Poor Turkeys
    整数拆分 [dp+多项式插值]
    王子 [费用流]
    [ARC083F] Collecting Balls [建二分图+环套树定向+建拓扑图+树的拓扑序计数]
    [BZOJ3196] 二逼平衡树 [权值线段树套位置平衡树]
    [TJOI2017][bzoj4889] 不勤劳的图书管理员 [线段树套线段树]
    [HNOI2015][bzoj4009] 接水果 [整体二分+扫描线]
    [bzoj3065] 带插入区间第k小值 [重量平衡树套线段树]
    [luogu3676] 小清新数据结构题 [树链剖分+线段树]
  • 原文地址:https://www.cnblogs.com/zzdbullet/p/9513685.html
Copyright © 2020-2023  润新知