设计程序,要求程序可以加入到一个多播组中并等待服务器发送数据包,并且程序还需要具有发送功能,如果收到数据包则把消息内容输出到终端

题目


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

分析


1.发送端需设置套接字的广播属性,使用setsockopt()函数,第三个参数需添加SO_BROADCAST;

2.接收端需设置同一端口号并加入组播地址,才能接受同组发送的信息,也需要使用setsockopt()函数,第三个参数需添加IP_ADD_MEMBERSHIP。

代码


/***********************************************************************************
*
*	file name:	udp_client.c
*	author	 :  cnzycwp@126.com 
*	date	 :  2024/06/04
*	function :  该案例是小组实现,小组中的每位成员都需要设计程序,要求程序可以加入到一个
*				多播组中并等待服务器发送数据包,并且程序还需要具有发送功能,如果收到数据
*				包则把消息内容输出到终端,消息内容格式 [消息来源IP  消息时间 ]:消息内容
* 	note	 :  None
*   version  :
*
*	CopyRight (c)  2023-2024   cnzycwp@126.com   All Right Reseverd 
*
* **********************************************************************************/
/************************************头文件*****************************************/
#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 <pthread.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
/***********************************************************************************/
/************************************全局变量***************************************/
int udp_socket;		//UDP套接字
/***********************************************************************************/
/*************************************结构体****************************************/
typedef struct lcd_time
{
    int year;		//年
    int mon;		//月
    int mday;		//日
    int wday;		//星期
    int hour;		//时
    int min;		//分
    int sec;		//秒

}LcdTime;
/***********************************************************************************/
/***********************************************************************************
*
*	name	 :	GetTime
*	function :  调用此函数可获取开发板的时间
*	param :  
*				none
*				
*	retval	 :  char *
*	author	 :  cnzycwp@126.com 
*	date	 :  2024/06/04
* 	note	 :  None
*   version  :
* 	
* *********************************************************************************/
//获取开发板时间
char *GetTime()
{
	//申请堆内存并定义一个记录LCD硬件时间的结构体指针
    LcdTime *tstm = (LcdTime *)calloc(1,sizeof(LcdTime));
	char * tstime = (char *)calloc(1,sizeof(char) * 32);
    //错误处理
    if (NULL == tstm)
    {
        printf("calloc for time failed\n");
		return NULL;
    }

	//4.获取当前系统时间,并把时间转换为特定格式“yy年mm月dd日 星期x tt:mm:ss”
	time_t Tseconds = time(NULL);
	struct tm *ft = localtime(&Tseconds);
	tstm->year = (ft->tm_year) + 1900;     //年从1900年开始
	tstm->mon  = (ft->tm_mon) + 1;         //月份从0开始
	tstm->mday = (ft->tm_mday);
	tstm->wday = (ft->tm_wday);
	tstm->hour = (ft->tm_hour);
	tstm->min  = (ft->tm_min);
	tstm->sec  = (ft->tm_sec);
	sprintf(
				tstime,
				"%d年%02d月%02d日,星期%d,%02d:%02d:%02d",
				tstm->year,
				tstm->mon,
				tstm->mday,
				tstm->wday,
				tstm->hour,
				tstm->min,
				tstm->sec
			);
        //fwrite(data_buffer,BUFFRSIZE,1,fp);
    return tstime;
}
/***********************************************************************************
*
*	name	 :	recv_udp_msg
*	function :  子线程的任务函数,该函数用于接收服务器发送的数据包
*	param :  
*				none
*				
*	retval	 :  none
*	author	 :  cnzycwp@126.com 
*	date	 :  2024/06/04
* 	note	 :  None
*   version  :
* 	
* *********************************************************************************/
void *recv_udp_msg(void *arg)
{

	//1.需要先绑定服务器的端口和地址
	struct sockaddr_in  host_addr;

	host_addr.sin_family 		= AF_INET; 					//协议族,是固定的
	host_addr.sin_port   		= htons(60000);				//目标端口,必须转换为网络字节序
	host_addr.sin_addr.s_addr   = htonl(INADDR_ANY);		//目标地址 "192.168.64.xxx"  已经转换为网络字节序  INADDR_ANY

	bind(udp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));

	//3.调用recvfrom等待接收数据,并且接收客户端的网络信息
	char buf[128] = {0};
	char *p = (char *)calloc(1,sizeof(char) * 32) ;
	struct sockaddr_in  client;
	socklen_t client_len = sizeof(client);

	while(1)
	{
		p = GetTime();
		recvfrom(udp_socket,buf,sizeof(buf), 0 ,(struct sockaddr *)&client,&client_len); //默认会阻塞
		printf("[%s,%s]:%s\n",inet_ntoa(client.sin_addr),p,buf);
		bzero(buf,sizeof(buf));
	}
}
// 运行客户端可执行文件   ./xxx  服务器端口  服务器地址

int main(int argc,char *argv[])
{
	//检查参数有效性
	// if (argc != 3)
	// {
	// 	fprintf(stderr, "argument is invaild ,errno:%d,%s\n",errno,strerror(errno));
	// 	exit(1);
	// }

	//1.创建UDP套接字             
	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);
	}

	//设置组播选项
	struct ip_mreqn mreqn;
	mreqn.imr_multiaddr.s_addr = inet_addr("226.66.66.66");		//组地址
	mreqn.imr_address.s_addr = htonl(INADDR_ANY);				//本地地址 inet_addr("192.168.64.97")
	mreqn.imr_ifindex = 0;										//接口索引
	
	setsockopt(udp_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn));


	//设置广播属性
	int opt = 1;
	setsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));

	//设置组播属性
	// setsockopt(udp_socket,IPPROTO_IP,IP_MULTICAST_TTL,&opt,sizeof(opt));

	//2.创建子线程
	pthread_t recv_thread;
	pthread_create(&recv_thread,NULL,recv_udp_msg,NULL);

	//2.向目标主机发送消息,需要设置目标端口和目标地址
	char buf[128] = {0};
	
	struct sockaddr_in  dest_addr;
	dest_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	dest_addr.sin_port   		= htons(60000);					//服务器端口,必须转换为网络字节序
	dest_addr.sin_addr.s_addr   = inet_addr("226.66.66.66");	//服务器地址 "192.168.64.xxx"  

	//3.发送客户端的上线时间
	while(1)
	{
		scanf("%s",buf);
		sendto(udp_socket,buf,strlen(buf),0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));

	}
	
	
	

	return 0;

}

结果


image

posted @ 2024-06-04 21:26  陳文鹏  阅读(14)  评论(0编辑  收藏  举报