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