📄 client.c
字号:
//有两个条件:1 进程必须加入多播组 2 进程必须捆绑某个端口(服务器的多播端口)到UDP套接口
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/types.h>
const char *host = "224.0.0.1";
const char *host2 = "192.168.0.13";
int main( int argc, char **argv )
{
char message[256];
struct ip_mreq mreq;
/*struct ip_mreq{
struct in_addr imr_multiaddr; // IPv4 class D multicast addr D类多播地址
struct in_addr imr_interface; // IPv4 addr of local interface 本地接口
};*/
int on = 1;
u_char ttl = 12;
int sockfd;
struct sockaddr_in servaddr;
socklen_t socklen;
sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
memset( &servaddr, 0, sizeof(servaddr) );//memset函数用来对一段内存空间全部设置为某个字符,常用于内存空间初始化。将已开辟内存空间 s 的首 n 个字节的值设为值 c
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(10000);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。
//将主机的无符号长整形数转换成网络字节顺序。
//为了方便在同一电脑上测试多播地址
if( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0 ) //SO_REUSEADDR 允许套接口和一个已在使用中的地址捆绑(参见bind())。
{
perror( "setsockopt to SO_REUSEADDR" );
exit(1);
}
printf( "setsockopt to SO_REUSEADDR\n" );
//允许接收本地回馈
on = 1;
if( setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &on, sizeof(on) ) < 0 ) //使能或禁止外出多播数据报的回馈
{
perror( "setsockopt IP_MULTICAST_LOOP " );
exit(1);
}
printf( "setsockopt IP_MULTICAST_LOOP\n" );
inet_pton(AF_INET, host, &mreq.imr_multiaddr.s_addr);//转换字符串到网络地址,并且多播地址设置为host,即“224.0.0.1”;
mreq.imr_interface.s_addr = htonl(INADDR_ANY); //设置本地地址
//进程必须加入多播组,在mreq结构中要指定多播IP地址,至于接口可以由系统自动分配
if( setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) ) < 0 ) //加入多播组
{
perror( "setsockopt IP_ADD_MEMBERSHIP " );
exit(1);
}
printf( "setsockopt IP_ADD_MEMBERSHIP \n" );
//系统缺省为TTL为1, 也就是只能在本子网段内多播,如果要跨网段需要修改TTL
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl) ) < 0 ) //指定外出多播数据报的TTL
{
perror( "setsockopt IP_MULTICAST_TTL " );
exit(1);
}
printf( "setsockopt IP_MULTICAST_TTL \n" );
//注意:进程必须捆绑该端口(即服务器的多播端口)到UDP套接口,至于套接口可以由系统自动分配也可以手动指定
if( bind( sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr) ) < 0 )
{
perror( "bind error" );
exit(1);
}
perror( "bind " );
on = 0;
while( on++ < 10 )
{
socklen = sizeof(servaddr);
if( recvfrom( sockfd, message, 256, 0, NULL, NULL ) < 0 ) //接受服务器发送的多播消息,10次
{
printf( "recvfrom error" );
continue;
}
printf( "%s\n", message );
}
if( setsockopt( sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq) ) < 0 ) //离开多播组
{
perror( "setsockopt IP_DROP_MEMBERSHIP " );
exit(1);
}
exit(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -