UDP的广播和组播

UDP的广播和组播

设计程序,创建UDP套接字,首先检查UDP套接字的广播选项是否启动,如果没有启动,则启动UDP套接字的广播选项。

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

int main()
{
    //1.创建socket套接字
    int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (udp_socket == -1)
	{
		fprintf(stderr, "udp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

    //2.获取UDP套接字的广播属性
	int flag = -1;
	socklen_t len = 4;
	getsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,(void *)&flag,&len);

	printf("flag = %d\n",flag); // 0

	//3.设置UDP套接字的广播属性
	int optval = 1;
	setsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,&optval,sizeof(optval));

	//4.获取UDP套接字的广播属性
	flag = -1;
	getsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,(void *)&flag,&len);
	printf("flag = %d\n",flag); // 非0

    //5.利用循环每隔5s想广播地址发送数据包
	char buf[128] = "I am teacher,this is test packet";
	
	struct sockaddr_in  dest_addr;
	dest_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	dest_addr.sin_port   		= htons(atoi(argv[1]));			//服务器端口,必须转换为网络字节序
	dest_addr.sin_addr.s_addr   = inet_addr(argv[2]);			//服务器地址 "192.168.64.xxx"  

	while(1)
	{
		sendto(udp_socket,buf,strlen(buf),0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
		sleep(5);
	}
	

	return 0;
    
}

小组实现,小组中的每位成员都需要设计程序,要求程序可以加入到一个多播组中并等待服务器发送数据包,并且程序还需要具有发送功能,如果收到数据包则把消息内容输出到终端, 消息内容格式 [消息来源IP 消息时间 ] : 消息内容

#include <stdio.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <locale.h>

#define MULADDR "192.168.136.200"
#define PORT 6666
struct sockaddr_in dest_addr;
int udp_socket;

//发送信息
void * send_msg(void *)
{
    char buf[128] = "HELLO WORLD";
    //向多播组发送内容
    while(1)
    {
        sendto(udp_socket, buf, strlen(buf), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
        sleep(5);
    }
    return NULL;
}

//接收信息
// void * recv_msg(void *)
// {
//     struct sockaddr_in source_addr;
//     socklen_t addr_len = sizeof(source_addr);  // 声明变量并初始化
//     char recvbuf[128];
//     // 获取当前时间
//     time_t current_time = time(NULL);
//     // 转换为本地时间
//     struct tm *tm_now = localtime(&current_time);
//     // 使用strftime格式化时间
//     char buffer[128];
//     strftime(buffer, sizeof(buffer), "%Y-%m-%d %H-%M-%S",tm_now); 
//     while(1)
//     {
//         //接收收到的信息
//         recvfrom(udp_socket,recvbuf,sizeof(recvbuf),0,(struct sockaddr *)&source_addr, &addr_len);
//         // 打印时间
//         printf("来自:%s,当前时间是:%s,内容:%s\n", inet_ntoa(source_addr.sin_addr),buffer,recvbuf);
//         bzero(recvbuf,sizeof(recvbuf));
//     }
// }
// 接收信息
void *recv_msg(void *) {
    struct sockaddr_in source_addr;
    socklen_t addr_len = sizeof(source_addr);  // 定义地址长度变量
    char recvbuf[128];
    
    while (1) {
        // 重置地址长度,防止被前次调用修改
        addr_len = sizeof(source_addr);
        
        // 接收数据
        ssize_t recv_size = recvfrom(
            udp_socket, 
            recvbuf, 
            sizeof(recvbuf) - 1,  // 预留一个字节给字符串终止符
            0, 
            (struct sockaddr *)&source_addr, 
            &addr_len  // 正确传递地址长度变量的指针
        );

        // 处理接收结果
        if (recv_size > 0) {
            recvbuf[recv_size] = '\0';  // 添加字符串终止符
            // 获取当前时间(实时更新)
            time_t now = time(NULL);
            struct tm *tm_info = localtime(&now);
            char time_buf[128];
            strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm_info);
            printf("来自:%s,时间:%s,内容:%s\n", 
                  inet_ntoa(source_addr.sin_addr), time_buf, recvbuf);
        } else if (recv_size == -1) {
            perror("recvfrom 错误");
            break;
        }
    }
    return NULL;
}

int main()
{
    //1.创建socket套接字
    udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (udp_socket == -1)
	{
		fprintf(stderr, "udp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

    //2.设置UDP套接字的组播属性,并加入组播组
    // struct ip_mreqn {
    //     struct in_addr imr_multiaddr; /* IP multicast group
    //                                      address */
    //     struct in_addr imr_address;   /* IP address of local
    //                                      interface */
    //     int            imr_ifindex;   /* interface index */
    // };
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr=inet_addr(MULADDR);
    mreq.imr_interface.s_addr=htonl(INADDR_ANY);
	setsockopt(udp_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));


    //3.创建的的套接字和本地端口和ip绑定
    struct sockaddr_in host_addr;
    host_addr.sin_family=AF_INET;
    host_addr.sin_port=htons(PORT);
    host_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    bind(udp_socket,(struct sockaddr *)&host_addr,sizeof(host_addr));

    // 4.向目标主机发送消息,需要设置目标端口和目标地址

	memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(PORT);
    dest_addr.sin_addr.s_addr = inet_addr(MULADDR);

    pthread_t recv_thread,send_thread;
    pthread_create(&recv_thread,NULL,recv_msg,NULL);
    pthread_create(&send_thread,NULL,send_msg,NULL);

    pthread_join(recv_thread,NULL);
    pthread_join(send_thread,NULL);

    close(udp_socket);
    return 0;
}
posted @ 2025-05-14 00:30  骗人就变小狗  阅读(316)  评论(0)    收藏  举报