首页 > 编程语言 >网络编程练习题---利用UDP协议实现组播通信

网络编程练习题---利用UDP协议实现组播通信

时间:2024-06-04 19:33:05浏览次数:32  
标签:练习题 UDP 组播 addr systimep tm 线程 include buf

目录

题目

image

解析

  1. 由于该题需要实现组播通信,所以我们需要将套接字文件句柄设置为组播属性,并将需要通信的用户端IP地址,加入组中。
  2. 由于组播通信需要实现一对多发送消息,所以还需要将套接字文件句柄的广播属性一并开启。
  3. 由于该题实现过程使用到了线程相关函数接口,所以编译时需要带上 “-pthread“ 选项

代码实现

/********************************************************************************
*
*	file name:	udp_group.c
*	author	 :  [email protected] 
*	date	 :  2024/06/04
*	function :  该案例是掌握UDP协议的组播通信方式
* 	note	 :  
*				想要实现组间通信,只需要对本地地址进行修改后,可实现组间通信,即一个用户
*				发送的消息,组间所有用户都能收到
*   version  :
*
*	CopyRight (c)  2023-2024   [email protected]   All Right Reseverd 
*
* ******************************************************************************/
/****************************头文件*********************************************/
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>

/****************************全局变量*********************************************/
int udp_socket;								//用于存储套接字文件的句柄

/****************************宏*********************************************/
#define PORT 	  60000 					//用户端运行进程的端口号
#define IP_HOST   "192.168.64.94"			//用户端本地IP地址
#define	IP_GROUP  "226.66.66.66"			//组播通信IP地址


/********************************************************************************
*
*	name	 :	recv_time
*	function :  实现获取当前系统时间,并对获取值进行固定格式的处理,获得更好的显示效果
*	param :  
*				none
*				
*	retval	 :  调用成功返回处理后的当前系统时间
*	author	 :  [email protected] 
*	date	 :  2024/06/04
* 	note	 : 
*				输出时间的格式固定为:"X年 X月 X日 星期X XX:XX:XX",可根据需要进行修改
*   version  :
* 	
* *****************************************************************************/
char *recv_time()
{
	//定义一个字符指针,用于存储获取的当前系统时间值
	char *buf =(char *)calloc(1,128);
	//定义一个字符数组,用于优化后的星期值
	char wekday[10];
	//利用time()获取当前系统时间,并将返回值存储起来
	time_t systime = time(NULL);
	//利用localtime()对获取值进行处理,并将处理后的数据写入目标文件中
	struct tm *systimep = localtime(&systime);
	systimep->tm_year += 1900;
	systimep->tm_mon += 1;
	//对获取星期数值进行判断,并进行美观优化
	if(systimep->tm_wday == 1)
		{
			strcpy(wekday, "一");
		}
		else if(systimep->tm_wday == 2) 
		{
			strcpy(wekday, "二");
		}
		else if(systimep->tm_wday == 3) 
		{
			strcpy(wekday, "三");
		}
		else if(systimep->tm_wday == 4) 
		{
			strcpy(wekday, "四");
		}
		else if(systimep->tm_wday == 5) 
		{
			strcpy(wekday, "五");
		}
		else if(systimep->tm_wday == 6) 
		{
			strcpy(wekday, "六");
		}
		else if(systimep->tm_wday == 7) 
		{
			strcpy(wekday, "日");
		}

		//将获取值按固定格式写入缓冲区中
		sprintf(buf, "%d年 %d月 %d日 星期%s %d:%d:%d", systimep->tm_year,
				systimep->tm_mon,
				systimep->tm_mday,
				wekday,
				systimep->tm_hour,
				systimep->tm_min,
				systimep->tm_sec);

		return buf;
}

/********************************************************************************
*
*	name	 :	recv_msg
*	function :  接收信息线程的任务函数
*	param :  
*				none
*				
*	retval	 :  none
*	author	 :  [email protected] 
*	date	 :  2024/06/04
* 	note	 :  
*				对应填写的IP地址,可以通过程序开头的宏定义进行修改
*   version  :
* 	
* *****************************************************************************/
void *recv_msg(void *arg)
{
	//将该线程的属性设置为分离属性,防止线程结束后变为僵尸线程
	pthread_detach(pthread_self());
	//绑定服务器的端口和地址
	struct sockaddr_in  host_addr;

	host_addr.sin_family 		= AF_INET; 						//协议族,UDP协议固定填写该宏定义
	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));

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

	//定义一个字符数组用于存储系统时间
	char *recvtime = (char *)calloc(128,1);
	while(1)
	{
		recvfrom(udp_socket,buf,sizeof(buf), 0 ,(struct sockaddr *)&client,&client_len); //函数标识定义为默认属性,即会阻塞
		recvtime = recv_time();
		if(client.sin_addr.s_addr == inet_addr(IP_HOST))
		{
			bzero(buf,sizeof(buf));
			continue;
			
		}
			printf("[%s] (%s): %s\n",inet_ntoa(client.sin_addr),recvtime,buf);
		bzero(buf,sizeof(buf));
	}
}

/********************************************************************************
*
*	name	 :	send_msg
*	function :  发送信息线程的任务函数
*	param :  
*				none
*				
*	retval	 :  none
*	author	 :  [email protected] 
*	date	 :  2024/06/04
* 	note	 :  
*				对应填写的IP地址,可以通过程序开头的宏定义进行修改
*   version  :
* 	
* *****************************************************************************/
void *send_msg(void *arg)
{
	//将该线程的属性设置为分离属性,防止线程结束后变为僵尸线程
	pthread_detach(pthread_self());
	
	//向目标主机发送消息,需要设置目标端口和目标地址
	char buf[128] = {0};
	
	struct sockaddr_in  dest_addr;
	dest_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	dest_addr.sin_port   		= htons(PORT);					//服务器运行进程的端口号,必须转换为网络字节序
	dest_addr.sin_addr.s_addr   = inet_addr(IP_GROUP);			//要发送对象的IP地址,必须转换为点分十进制字符串形式

	while(1)
	{
		//阻塞等待获取用户从键盘输入的信息
		scanf("%s", buf);
		//发送获取到的用户输入信息
		sendto(udp_socket,buf,strlen(buf),0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
	}

	
}

int main(int argc,char *argv[])
{
	
	//创建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);
	}

	//将套接字文件的广播属性设置为开启
	int flag = 1;
	socklen_t flag_len = sizeof(flag);
	setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, (void *)&flag, flag_len);

	//将套接字文件的组播属性设置为开启
	struct ip_mreqn ip_grop;
	ip_grop.imr_multiaddr.s_addr = inet_addr(IP_GROUP);//设置组播地址
	ip_grop.imr_address.s_addr = inet_addr(IP_HOST); //设置要加入组的本地地址
	ip_grop.imr_ifindex = 0;								 //设置为默认属性,由系统分配端口

	socklen_t ip_len = sizeof(ip_grop);
	setsockopt(udp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&ip_grop, ip_len);
	
	//创建两个线程,分别用于发送数据和接受数据
	pthread_t send;
	pthread_t recv;
	pthread_create(&send, NULL, send_msg, NULL);
	pthread_create(&recv, NULL, recv_msg, NULL);

	//关闭主线程
	pthread_exit(NULL);

	return 0;

}

标签:练习题,UDP,组播,addr,systimep,tm,线程,include,buf
From: https://www.cnblogs.com/fly-home/p/18231570

相关文章

  • udp协议实现组播功能
    /****************************************************************************************************************************************filename:multicast.c*author:[email protected]*date:2024/06/04*brief:小组实现,小组中的每位......
  • UDP练习题——实现将自己加入到多播组中并等待服务器发送数据包
    设计程序,要求程序可以加入到一个多播组中并等待服务器发送,数据包,并且程序还需要具有发送功能,如果收到数据包则把消息内容输出到终端,消息内容格,式「消息来源IP消息时间1:消息内容多播地址和端口号/*************************************************************************......
  • JAVA面向对象练习题
    题目要求:        定义图书类(Book),要求有属性name(书名),price(价格),author(作者),对Book类进行封装。在测试类里的主方法中创建3本图书对象,并赋值。创建一个长度为3的Book类数组,在数组里,存放这3个图书对象。题目分析:  图书类Book:    属性:   ......
  • 每日两道练习题-- 带你学会SQL server(获取所有非manager员工当前的薪水情况,对所有员工
    SQLServer在实际场景中的应用非常广泛,以下是一些主要的应用领域:企业级应用:SQLServer具有高度的稳定性、可靠性和安全性,非常适合用于企业级应用。例如,企业资源规划(ERP)系统、客户关系管理(CRM)系统、人力资源管理(HRM)系统等,这些系统都需要处理大量的数据和复杂的业务逻辑,SQLS......
  • TCP和UDP的区别
    TCP(传输控制协议)和UDP(用户数据报协议)的区别TCP(TransmissionControlProtocol):1.面向连接:在发送数据之前,TCP需要通过三次握手(SYN、SYN+ACK、ACK)来建立连接,以确保双方可收发数据。2.可靠性:TCP会确保数据在传输过程中的顺序性和完整性。如果数据包丢失或错误,TCP会自动请求重新......
  • UDP通信
    UDP通信特点:无连接、不可靠通信。不事先建立连接;发送端每次把要发送的数据(限制在64KB内)、接收端IP、等信息封装成一个数据包,发出去就不管了。Java提供了一个java.net.DatagramSocket类来实现UDP通信。DatagramSocket:用于创建客户端、服务端构造器......
  • (十三)统计学基础练习题七(选择题T301-350)
    本文整理了统计学基础知识相关的练习题,共50道,适用于想巩固统计学基础或备考的同学。来源:如荷学数据科学题库(技术专项-统计学二)。序号之前的题请看往期文章。301)302)303)304)305)306)307)308)309)310)311)312)313)314)315)316)317)318)319)320)321)322)......
  • C语言练习题之——从简单到烧脑(13)(每日两道)
    打印爱心1.1:普通输出爱心#include<stdio.h>intmain(){ printf("******************\n");//7(代表边上的空格) printf("******************************\n");//4 printf("************************************\n&quo......
  • 「网络编程」基于 UDP 协议实现回显服务器
    ......
  • 使用select实现一个基于UDP的一对一即时聊天程序。
    注意事项UDP通信时,client要先给server发送消息,这样server才能知道client的信息代码//server#include<func.h>#defineBUFFSIZE1024intmain(){intsfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd==-1){perror("socket");}structsockad......