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
原文地址:https://www.cnblogs.com/zzdbullet/p/9513685.html