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后可以获取客户端信息