使用udp实现双向通信(聊天室)

本期和大家分享的是使用UDP实现聊天室的功能,本期日常小项目实现的是使用socket套接字实现UDP编程,使得能够进行通信;
使用到的主要函数接口有socket,bind,sendto,recvfrom,htons,inet_addr等在网络通信中需要用到的函数接口,在后续的TCP通信中也会使用到;下面带大家来看下具体实现:
1.主要分为两个进程,每个进程中都有两个线程负责收发;功能在代码注释中;

#include "head.h"

pthread_t tid1;
pthread_t tid2;
int sockfd = -1;		//socket通信文件描述符
ssize_t nsize = 0;
char name[32];			//存储用户姓名
void *sendfun(void *arg)
{
	msg_t tmpmsg;
	struct sockaddr_in recvaddr;		//存放协议族端口号以及ip地址的结构体

	recvaddr.sin_family = AF_INET;		//IPV4协议族
	recvaddr.sin_port = htons(50001);	//讲整形变量的端口号转变成网络字节序(因为整数一般存储方式为小端存储,但是IPV4有它特定的网络字节序)
	recvaddr.sin_addr.s_addr = inet_addr("192.168.209.129");  //将点分十进制转化为IPV4能够识别的二进制数
	
	while(1)
	{
		memset(&tmpmsg, 0, sizeof(tmpmsg.mytext));
		strcpy(tmpmsg.name, name);					//拷贝主进程中的用户昵称
		gets(tmpmsg.mytext);						//接收需要发送的消息

		nsize = sendto(sockfd, &tmpmsg, sizeof(tmpmsg), 0, (struct sockaddr *)(&recvaddr), sizeof(recvaddr));  //发送消息
		if (-1 == nsize)
		{
			perror("fail to sendto");
			return NULL;
		}

		if (!strcmp(tmpmsg.mytext, "q"))	//发送q结束聊天
		{
			break;
		}

	}
	close(sockfd);

	pthread_cancel(tid2);

	return NULL;
}

void *recvfun(void *arg)
{
	msg_t tmpmsg;

	while (1)
	{
		memset(&tmpmsg, 0, sizeof(msg_t));
		nsize = recvfrom(sockfd, &tmpmsg, sizeof(msg_t), 0, NULL, NULL); //接收消息
		if (-1 == nsize)
		{
			perror("fail to recvfrom");
			return NULL;
		}
		if (!strcmp(tmpmsg.mytext, "q"))
		{
			break;
		}

		printf("%s:%s\n", tmpmsg.name, tmpmsg.mytext);
	}

	close(sockfd);
	pthread_cancel(tid1);
	return NULL;
}

int main(int argc, const char *argv[])
{
	int ret = 0;
	struct sockaddr_in senaddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd)
	{
		perror("fail to sockfd");
		return -1;
	}

	senaddr.sin_family = AF_INET;
	senaddr.sin_port = htons(50000);
	senaddr.sin_addr.s_addr = inet_addr("192.168.209.128");

	ret = bind(sockfd, (struct sockaddr *)&senaddr, sizeof(senaddr));	//绑定自己的端口号和IP(清楚本进程是谁)
	if (-1 == ret)
	{
		perror("fail to bind");
		return -1;
	}

	printf("请输入您的昵称:");
	gets(name);
	putchar('\n');

	pthread_create(&tid1, NULL, sendfun, NULL);
	pthread_create(&tid2, NULL, recvfun, NULL);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);

	return 0;
}

2.第二个进程和第一个进程非常相似,但是小伙伴们必须理解你在给谁发数据,所以必须把IP地址和端口号理解清楚;

#include "head.h"

pthread_t tid1;
pthread_t tid2;
int sockfd = -1;
struct sockaddr_in recvaddr;
char tmpbuff[1024] = {0};
int ret = 0;
ssize_t nsize = 0;
char name[32];
void *sendfun(void *arg)
{
	msg_t tmpmsg;
	struct sockaddr_in senaddr;
	
	senaddr.sin_family = AF_INET;
	senaddr.sin_port = htons(50000);
	senaddr.sin_addr.s_addr = inet_addr("192.168.209.128");
	while(1)
	{
		memset(&tmpmsg, 0, sizeof(msg_t));
		strcpy(tmpmsg.name, name);
		gets(tmpmsg.mytext);

		nsize = sendto(sockfd, &tmpmsg, sizeof(msg_t), 0, (struct sockaddr *)(&senaddr), sizeof(senaddr));
		if (-1 == nsize)
		{
			perror("fail to sendto");
			return NULL;
		}
		if (!strcmp(tmpmsg.mytext, "q"))
		{
			break;
		}
	}

	close(sockfd);
	pthread_cancel(tid2);

	return NULL;
}


void *recvfun(void *arg)
{
	msg_t tmpmsg;

	while (1)
	{
		memset(&tmpmsg, 0, sizeof(tmpmsg));
		nsize = recvfrom(sockfd, &tmpmsg, sizeof(msg_t), 0, NULL, NULL);
		if (-1 == nsize)
		{
			perror("fail to recvfrom");
			return NULL;
		}
		if (!strcmp(tmpmsg.mytext, "q"))
		{
			break;
		}

		printf("%s:%s\n", tmpmsg.name, tmpmsg.mytext);
	}

	close(sockfd);
	pthread_cancel(tid1);
	return NULL;
}
	
int main(int argc, const char *argv[])
{

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd)
	{
		perror("fail to sockfd");
		return -1;
	}

	recvaddr.sin_family = AF_INET;
	recvaddr.sin_port = htons(50001);
	recvaddr.sin_addr.s_addr = inet_addr("192.168.209.129");

	ret = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
	if (-1 == ret)
	{
		perror("fail to bind");
		return -1;
	}

	printf("请输入昵称:");
	gets(name);
	putchar('\n');

	pthread_create(&tid1, NULL, sendfun, NULL);
	pthread_create(&tid2, NULL, recvfun, NULL);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);


	return 0;
}

进行双向通信的运行结果展示一下:
在这里插入图片描述
在这里插入图片描述

以上内容就是本期的分享内容,希望通过这个小项目可以让大家理解UDP通信中最基本的函数操作接口;不懂就问哦!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于UDP(User Datagram Protocol)实现双向可靠通信需要借助一些机制和算法来确保数据的可靠传输。 首先,双向通信意味着通信的双方都可以发送和接收数据。每个通信实体都需要创建一个UDP Socket,并且绑定相应的IP地址和端口。这样,双方可以互相发送和接收数据。 其次,可靠传输需要使用一些机制来确保数据的完整性和准确性。一种常见的机制是使用序号和确认机制。发送方将数据分割成小的数据包,并为每个数据包添加一个唯一的序号。接收方收到数据包后发送一个确认消息给发送方,确认接收到该数据包。如果发送方没有收到确认消息,它会认为数据包丢失,然后重新发送该数据包。 此外,超时重传机制也是保证数据可靠传输的重要手段。发送方在发送完一个数据包后会启动一个定时器。如果在特定的时间内未收到确认消息,发送方会重新发送数据包,直到收到确认消息或达到最大重传尝试次数。 还可以使用拥塞控制算法来避免网络拥塞。当网络拥塞时,发送方可以降低发送速率,以避免丢包和延迟。 在双向通信中,双方需要相互交流,因此可以采用双工通信模式。双工通信允许双方同时发送和接收数据,这样可以更高效地完成通信。 总结来说,基于UDP实现双向可靠通信需要使用序号和确认机制、超时重传机制、拥塞控制算法和双工通信模式。这些机制和算法的结合可以有效地保证数据的可靠传输和双方通信的顺畅进行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值