UDP服务器实现群发功能

本文章主要讲解用UDP实现类似QQ群的功能,需要做到一个客户端发送消息,其它在线的客户端都能接收到消息

1.实现思路

在这里插入图片描述
在服务端由于需要连接多个客户端,可以选用链表储存客户信息,服务器接收到客户端的消息后,给链表中所有用户都发消息,其中客户端既有发送的操作也需要有接收的操作。

注意:客户端需要至少一次向服务器发送过信息,此时服务器才会记录客户端的IP+port。

2.具体代码

客户端
客户端既有发送的操作也需要有接收的操作,所以我们可以引入线程操作。

#include "head.h"

void *recv_message(void *arg)
{
	int sockfd = *((int *)arg);
	char buf[100]={0};
	int n = 0;

	while(1)
	{
		memset(buf,0,sizeof(buf));
		n = recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
		if(n < 0)
		{
			perror("Fail to recvfrom");
		}
		printf("Recv : %s\n",buf);
	}
	exit(EXIT_FAILURE);
}

int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	socklen_t addrlen = sizeof(server_addr);
	char buf[100]={0};
	int n = 0;
	pthread_t tid = 0;
	int ret = 0;

	if(argc != 3)
	{
		fprintf(stderr,"Usage : %s ip port\n",argv[0]);
		return -1;

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

	ret = pthread_create(&tid,NULL,recv_message,(void *)&sockfd);
	if(ret != 0)
	{
		fprintf(stderr,"Fail pthread_create\n");
		return -1;
	}

	bzero(&server_addr,addrlen);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(atoi(argv[2]));
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);

	while(1)
	{
		memset(buf,0,sizeof(buf));
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1] = '\0';

		n = sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&server_addr,addrlen);
		if(n < 0)
		{
			perror("sendto");
			return -1;
		}
	}
	close(sockfd);
	return 0;
}

服务端

int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	socklen_t addrlen = sizeof(server_addr);
	char buf[100]={0};
	int n = 0;

	if(argc != 3)
	{
		fprintf(stderr,"Usage : %s ip port\n",argv[0]);
		return -1;

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

	bzero(&server_addr,addrlen);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(atoi(argv[2]));
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	if(bind(sockfd,(struct sockaddr*)&server_addr,addrlen) < 0)
	{
		perror("bind");
		return -1;
	}

	LinkNode *head = creare_empty_linklist();
	while(1)
	{
		bzero(buf,sizeof(buf));
		n = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&client_addr,&addrlen);
		if(n < 0)
		{
			perror("recvfrom");
			return -1;
		}
		if(0 == strncmp(buf,"quit",4))
		{
			break;
		}

		printf("client IP: %s\n",inet_ntoa(client_addr.sin_addr));
		printf("client port: %d\n",ntohs(client_addr.sin_port));
		printf("recv_buf: %s\n",buf);

		if(find_linklist(head,client_addr) == false)
		{
			insert_head_linklist(head,client_addr);	 
		}

		boardcast_message(sockfd,head,buf,n,client_addr);
		
	}
	return 0;
}

在服务器中因为要保存多个客户端的信息,所以我们还需要补充一个链表文件。

#include "head.h"

LinkNode *creare_empty_linklist()
{
	LinkNode *head = (LinkNode *)malloc(sizeof(LinkNode));
	if(NULL == head)
	{
		printf("Fail to malloc\n");
		return NULL;
	}

	head->next = NULL;

	return head;
}

void insert_head_linklist(LinkNode *head,DataType data){
	LinkNode *node = (LinkNode *)malloc(sizeof(LinkNode));
	if(NULL == node)
	{
		fprintf(stderr,"fail head\n");
		return ;
	}
	memset(node,0,sizeof(LinkNode));
	node->data = data;
	node->next = head->next;
	head->next = node;
}

bool is_empty(LinkNode *head){
	return head->next == NULL ? true : false;
}

void insert_tail_linklist(LinkNode *head,DataType data){
	LinkNode *node = (LinkNode *)malloc(sizeof(LinkNode));
	if(node == NULL)
	{
		printf("error node\n");
		return ;
	}
	memset(node,0,sizeof(LinkNode));
	LinkNode *temp = NULL;
	for(temp = head->next;temp->next != NULL;temp = temp->next)
	{
	}
	node->data = data;
	node->next = temp->next;
	temp->next = node;
}

bool find_linklist(LinkNode *head,DataType data){
	LinkNode *temp = head;
	while(temp->next != NULL)
	{
		if(memcmp(&(temp->data),&data,sizeof(DataType)) == 0)
		{
			return true;
		}
		temp = temp->next;
	}
	return false;
}

bool boardcast_message(int sockfd,LinkNode *head,char *buf,int len,DataType data)
{
	LinkNode *temp = head->next;
	int n = 0;
	while(temp != NULL)
	{ 
		n = sendto(sockfd,buf,len,0,(struct sockaddr *)&(temp->data),sizeof(DataType));
		if(n < 0)
		{
			perror("Fail to sendto");
		}
		temp = temp->next;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值