网络编程中UDP协议通信

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
//使用前应设置端口号  通信时应保持一致
#define DESTHOST 60000

用于发送信息使用的函数接口

注:创建套接字时第二个参数应指定UDP协议指定的宏

/*******************************************************************
 *
 *	函数名称:	sendinfo
 *	函数功能:   使用UDP协议向指定IP发送信息的线程
 *	函数参数:
 *	返回结果:
 * 	注意事项:   None
 * 	函数作者:   mailLinL@163.com
 *	创建日期:   2024/06/05
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
void *sendinfo(void *arg)
{
	// 1.创建udp套接字
	int socketfd = socket(AF_INET,	  // IPV4指定参数
						  SOCK_DGRAM, // UDP指定参数
						  0);
	if (socketfd == -1) // 错误处理,套接字文件描述符为-1,表示创建失败
	{
		fprintf(stderr, "udp socket error,errno:%d,%s\n", errno, strerror(errno));
		exit(1);
	}

	// 2.定义数据缓冲区
	char sendbuf[128] = {0};									  // 用于储存想要发送的数据缓冲区
	char timenow[128] = {0};									  // 用于储存发送数据的时间缓冲区
	char ipbuf[30] = {0};										  // 定义缓冲区储存IP地址
	struct tm *now = (struct tm *)calloc(1, sizeof(struct tm *)); // 用于记录当前时间的结构体
	time_t data;												  // 记录标准秒数
	struct sockaddr_in destaddr;								  // 定义记录套接字目标主机信息的结构体
	destaddr.sin_family = AF_INET;								  // IPV4指定参数
	destaddr.sin_port = htons(DESTHOST);						  // 服务器端口,必须转换为网络字节序

	while (1)
	{
		printf("请输入想要发送的消息:\n");
		data = time(NULL);										// 获取标准秒数
		now = localtime(&data);									// 将标准秒数转换成指定格式存入结构体中
		sprintf(timenow, "%04d年%02d月%02d日 %02d:%02d:%02d  ", // 将指定格式的时间写入缓冲区中
				now->tm_year + 1900,
				now->tm_mon + 1,
				now->tm_mday,
				now->tm_hour,
				now->tm_min,
				now->tm_sec);
		scanf("%s", sendbuf);	  // 将想要发送的数据存入缓冲区中
		strcat(timenow, sendbuf); // 将日期和发送的信息拼接存入timenow缓冲区
		printf("%s\n", timenow);
		printf("请输入想要通信的IP地址(例:192.168.64.xxx):\n");
		scanf("%s", ipbuf); // 从终端输入想要通信的目标主机IP
		destaddr.sin_addr.s_addr = inet_addr(ipbuf);
		// 向目标主机发送信息
		sendto(socketfd,					 // 套接字文件描述符
			   timenow,						 // 想要发送的信息缓冲区
			   sizeof(timenow),				 // 缓冲区大小
			   0,							 // 发送信息的标志,默认为0
			   (struct sockaddr *)&destaddr, // UDP指定目标主机IP信息
			   sizeof(destaddr));			 // 主机IP结构体的大小
	}

	return 0;
}

用于接收信息的函数接口

注:创建套接字时第二个参数应指定UDP协议指定的宏

/*******************************************************************
 *
 *	函数名称:	recvinfo
 *	函数功能:   使用UDP协议接收信息的线程
 *	函数参数:
 *	返回结果:
 * 	注意事项:   None
 * 	函数作者:   mailLinL@163.com
 *	创建日期:   2024/06/05
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
void *recvinfo(void *arg)
{
	// 1.创建udp套接字
	int socketfd = socket(AF_INET,	  // IPV4指定参数
						  SOCK_DGRAM, // UDP指定参数
						  0);
	if (socketfd == -1) // 错误处理,套接字文件描述符为-1,表示创建失败
	{
		fprintf(stderr, "udp socket error,errno:%d,%s\n", errno, strerror(errno));
		exit(1);
	}
	// 2.创建接收数据缓冲区
	char recvbuf[128] = {0};
	struct sockaddr_in clent;				   // 定义接收套接字源信的结构体
	clent.sin_family = AF_INET;				   // IPV4指定参数
	clent.sin_port = htons(DESTHOST);		   // 服务器端口,必须转换为网络字节序
	clent.sin_addr.s_addr = htonl(INADDR_ANY); // 选择接收所有IP来源的信息

	// 3.将套接字与接收结构体进行绑定
	bind(socketfd, (struct sockaddr *)&clent, sizeof(struct sockaddr));
	struct sockaddr_in sourceaddr;
	socklen_t le = sizeof(sourceaddr);

	while (1)
	{
		recvfrom(socketfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sourceaddr, &le);
		printf("[%s]:%s\n", inet_ntoa(sourceaddr.sin_addr), recvbuf);
		bzero(recvbuf, sizeof(recvbuf));
	}
}

主函数中的测试程序

两个函数应该同时运行,recvfrom()函数默认会阻塞,并且不应该影响其他任务,所以使用两个线程运行

int main()
{
	// 2.创建接收数据的线程
	pthread_t recvthread;
	pthread_create(&recvthread, NULL, recvinfo, NULL);

	// 1.创建发送数据的线程
	pthread_t sendthread;
	pthread_create(&sendthread, NULL, sendinfo, NULL);

	// 3.等待子线程结束并释放资源
	pthread_join(sendthread, NULL);
	pthread_join(recvthread, NULL);

	return 0;
}

编译指令:

 gcc "udp_pathname".c -o "udp_pathname" -pthread

运行指令:

./"udp_pathname"

以下为发送消息

image

以下为指定ip所接收到的信息

image

注意事项:

1.UDP协议通信是一种面向无连接,不可靠的通信方式,所以在使用前应获得对方IP,以及端口号。
2.使用该协议发送信息,当对方不在线时,会出现丢包情况,所以使用前请确保双方同时在线

posted @   林大官人995  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示