基于UDP实现直播间聊天的功能

news2024/12/23 13:45:37
需求:
	软件划分为用户客户端和主播服务端两个软件client.c和server.c 

用户客户端负责:
    1.接收用户的昵称
    2.接收用户输入的信息,能够将信息发送给服务端
    3.接收服务端回复的数据信息,并完成显示

主播服务端负责:
    1.对所有加入直播间的用户的IP地址和端口实现管理(加入、退出)
    2.当有新的客户端加入时,能够向所有客户端提示:"欢迎 XXX 用户进入直播间"
    3.当有客户端退出时,能够向所有客户端提示:"XXX 离开直播间"
    4.能够实现客户端聊天内容的转发,当某个客户端发送聊天信息时,能够将该信息转给除了该用户之外聊天室内所有其余客户端用户

head.h文件

#ifndef __HEAD_H__
#define __HEAD_H__

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/in.h>

struct address
{
	int mark;
	struct sockaddr_in addr;
};

struct msgbuf{
	int type;
	char name[32];
	char text[512];
};

#define MSG_TYPE_START		100
#define MSG_TYPE_END		200
#define MSG_TYPE_CHAT		300
#define RECV_ADDR			"192.168.1.152"
#define RECV_PORT			50000

#endif

client.c

#include "head.h"

char name[32] = {0};
int sockfd = 0;
struct sockaddr_in recvaddr;
pthread_t tid_send;		//发线程
pthread_t tid_recv;		//收线程

void *sendfun(void *arg)
{
	struct msgbuf sendmsg;	
	ssize_t nsize = 0;

	while (1)
	{
		memset(&sendmsg, 0, sizeof(sendmsg));
		sendmsg.type = MSG_TYPE_CHAT;
		sprintf(sendmsg.name, "%s", name);
		gets(sendmsg.text);
		
		if (!strcmp(sendmsg.text, ".quit"))
		{
			sendmsg.type = MSG_TYPE_END;
		}

		nsize = sendto(sockfd, &sendmsg, sizeof(sendmsg), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
		if (-1 == nsize)
		{
			perror("fail to sendto");
			return NULL;
		}

		if (sendmsg.type == MSG_TYPE_END)
		{
			break;
		}
	}

	pthread_cancel(tid_recv);
	
	return NULL;
}

void *recvfun(void *arg)
{
	struct msgbuf recvmsg;
	ssize_t nsize = 0;

	while (1)
	{
		memset(&recvmsg, 0, sizeof(recvmsg));
		nsize = recvfrom(sockfd, &recvmsg, sizeof(recvmsg), 0, NULL, NULL);
		if (-1 == nsize)
		{
			perror("fail to recvfrom");
			return NULL;
		}

		if (recvmsg.type == MSG_TYPE_CHAT)
		{
			printf("%s(%s:%d)>%s\n", recvmsg.name, RECV_ADDR, RECV_PORT, recvmsg.text);
		}
		else if (recvmsg.type == MSG_TYPE_END)
		{
			break;
		}
	}
	
	pthread_cancel(tid_send);

	return NULL;
}

int main(void)
{
	struct msgbuf sendmsg;
	ssize_t nsize = 0;

	recvaddr.sin_family = AF_INET;
	recvaddr.sin_port = htons(RECV_PORT);
	recvaddr.sin_addr.s_addr = inet_addr(RECV_ADDR);

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

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd)
	{
		perror("fail to socket");
		return -1;
	}
	
	memset(&sendmsg, 0, sizeof(sendmsg));
	sendmsg.type = MSG_TYPE_START;
	sprintf(sendmsg.name, "%s", name);
	nsize = sendto(sockfd, &sendmsg, sizeof(sendmsg), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
	if (-1 == nsize)
	{
		perror("fail to sendto");
		return -1;
	}

	pthread_create(&tid_send, NULL, sendfun, NULL);
	pthread_create(&tid_recv, NULL, recvfun, NULL);

	pthread_join(tid_send, NULL);
	pthread_join(tid_recv, NULL);

	close(sockfd);

	return 0;
}

server.c

#include "head.h"

struct address ClientIpList[100];

int AddClientIp(struct sockaddr_in TmpAddr)
{
	int i = 0;

	for(i = 0;i < 100;++i)
	{
		if(ClientIpList[i].mark == 0)
		{
			ClientIpList[i].addr = TmpAddr;
			ClientIpList[i].mark = 1;
			break;
		}
	}

	return 0;
}
int DelClientIp(struct sockaddr_in TmpAddr)
{
	int i = 0;

	for(i = 0;i < 100;++i)
	{
		if(0 == memcmp(&TmpAddr,&ClientIpList[i].addr,sizeof(TmpAddr)))
		{
			ClientIpList[i].mark = 0;
			break;
		}
	}

	return 0;
}

int BoardcastClientIp(int sockfd,struct sockaddr_in TmpAddr,struct msgbuf TmpMes)
{
	int i = 0;
	ssize_t nsize = 0;
	for(i = 0;i < 100;++i)
	{
		if(ClientIpList[i].mark == 0)
		{
			continue;
		}

		if(0 != memcmp(&TmpAddr,&ClientIpList[i].addr,sizeof(TmpAddr)))
		{
			nsize = sendto(sockfd,&TmpMes,sizeof(TmpMes),0,(struct sockaddr *)&ClientIpList[i].addr,sizeof(ClientIpList[i].addr));
			if(-1 == nsize)
			{
				continue;
			}
		}
	}

	return 0;
}


int main(void)
{
	int sockfd = 0;
	int ret = 0;
	ssize_t nsize = 0;
	struct msgbuf recvmes;
	struct sockaddr_in recvaddr;
	struct sockaddr_in sendaddr;
	socklen_t addrlen = sizeof(sendaddr);

	recvaddr.sin_family = AF_INET;
	recvaddr.sin_port = htons(RECV_PORT);
	recvaddr.sin_addr.s_addr = INADDR_ANY;

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

	memset(&ClientIpList,0,sizeof(ClientIpList));
	while (1)
	{
		memset(&recvmes, 0, sizeof(recvmes));
		nsize = recvfrom(sockfd, &recvmes, sizeof(recvmes), 0,(struct sockaddr *)&sendaddr, &addrlen);
		if (-1 == nsize)
		{
			perror("fail to recvfrom");
			return -1;
		}
		
		
		if(recvmes.type == MSG_TYPE_START)
		{
			AddClientIp(sendaddr);
			recvmes.type = MSG_TYPE_CHAT;
			sprintf(recvmes.text,"%s",recvmes.name);
		}
		else if (recvmes.type == MSG_TYPE_END)
		{
			DelClientIp(sendaddr);
			recvmes.type = MSG_TYPE_CHAT;
			sprintf(recvmes.text,"%s",recvmes.name);
		}
		
		if (recvmes.type == MSG_TYPE_CHAT)
		{
			BoardcastClientIp(sockfd,sendaddr,recvmes);
		}
	}

	close(sockfd);

	return 0;
}

结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1500070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于uniapp cli项目开发的老项目,运行报错path.replace is not a function

项目&#xff1a;基于uniapp cli的微信小程序老项目 问题&#xff1a;git拉取代码&#xff0c;npm安装包时就报错&#xff1b; cnpm能安装成功包&#xff0c;运行报错 三种方法尝试解决&#xff1a; 更改代码&#xff0c;typeof pathstring的话&#xff0c;才走path.replace…

mysql的语法总结2

命令&#xff1a; mysql -u 用户名 -p mysql登录 命令&#xff1a;create database u1 创建数据库u1 查询数据库 使用数据库u1 创建表department 查询表department ALTER TABLE 表名 操作类型&#xff1b; 操作类型可以有以下的操作&#xff1a; 添加列&#x…

【算法 高级数据结构】树状数组:一种高效的数据结构(一)

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;算法题、 基础算法~赶紧来学算法吧 &#x1f4a1;往期推荐&#xff1a; 【算法基础 & 数学】快速幂求逆元&#xff08;逆元、扩展欧几里得定理、小费马定理&#x…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现双快门采集两张曝光时间非常短的图像(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现双快门采集两张曝光时间非常短的图像&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机定序器功能的技术背景Baumer工业相机通过NEOAPI SDK使用定序器功能预期的相机动作技术限制定序器的工作原理 Baumer工业相机通过…

20个Python函数程序实例

前面介绍的函数太简单了&#xff1a; 以下是 20 个不同的 Python 函数实例 下面深入一点点&#xff1a; 以下是20个稍微深入一点的&#xff0c;使用Python语言定义并调用函数的示例程序&#xff1a; 20个函数实例 简单函数调用 def greet():print("Hello!")greet…

WPF Border控件 基本使用

Border 基本使用 1单线效果 代码&#xff1a; <Border Grid.Row"0" BorderThickness"0,0,0,1" BorderBrush"Red" /> 说明&#xff1a; BorderThickness"0,0,0,1" 可以分别设置四条边&#xff0c;顺序是&#xff1a;左 上 右…

【微信小程序】基本语法

目录 一、列表渲染&#xff08;包括wx:for改变默认&#xff09; 二、事件冒泡和事件捕获 三、生命周期 一、列表渲染&#xff08;包括wx:for改变默认&#xff09; 1、列表渲染(wx-for、block 改变默认wx:for item等) <view> {{msg}} </view> //渲染跟普通vu…

云计算项目十:ES集群安装|部署kibana

ES集群安装 部署ES集群&#xff0c;用于ELK日志分析平台的构建 es-0001 主机更改 /etc/hosts [rootes-0001 ~]# vim /etc/hosts 192.168.1.71 es-0001 192.168.1.72 es-0002 192.168.1.73 es-0003 192.168.1.74 kibana 192.168.1.75 logstash # 将最新的/etc/hosts配置文件更…

Python绘图-12地理数据可视化

Matplotlib 自 带 4 类别 地理投影&#xff1a; Aitoff, Hammer, Mollweide 及 Lambert 投影&#xff0c;可以 结 合以下四 张 不同 的 图 了解四 种 不同投影 区别 。 12.1Aitoff投影 12.1.1图像呈现 12.1.2绘图代码 import numpy as np # 导入numpy库&#xff0c;用于…

2024年大语言模型的微调

一个LLM的生命周期包含多个步骤&#xff0c;下面将讨论这个周期中最活跃、最密集的部分之一 -- fine-tuning(微调)过程。 LLM的生命周期 下面展示了LLM的生命周期&#xff1a; 愿景和范围&#xff1a;首先需要定义项目的愿景&#xff0c;你想让你的LLM作为一个更加通用的工具…

双体系Java学习之关键字,标识符以及命名规范

刚开学&#xff0c;然后之前的课程暂时停在了多态&#xff0c;接下来开始跟着学校的步伐重新开始学一下&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 之前的课程也会找个时间补起来的&#xff0c;谢谢大家&#xff01; 关键字 标识符 命名规范

STM 32 HAL库 内部FLash读写调试的问题

问题1&#xff1a;STM32G0 系列 256KB内部FLash大小&#xff0c;无法读写 分析&#xff1a;从STM32F103C8 移植过来的Flash操作代码&#xff0c;发现无法进行读写&#xff0c;返回 HAL_ERROR 错误&#xff0c;随后&#xff0c;检查在写之前是否擦除成功&#xff0c;检查代码发…

Oracle VM VirtualBox 安装完Ubuntu系统后一直提示安装Ubuntu

是因为存储设置有问题&#xff0c;把Ubuntu镜像添加进去了,移除后重启虚拟机就不会提示了 以下是配置的移除后的界面。

羊大师揭秘,女性喝羊奶有什么好处

羊大师揭秘&#xff0c;女性喝羊奶有什么好处 女性喝羊奶有多种好处。首先&#xff0c;羊奶富含钙元素&#xff0c;有助于预防女性体内缺钙和老年女性骨质疏松&#xff0c;从而增强骨骼密度。其次&#xff0c;羊奶中的色氨酸和烟酸等成分有助于促进睡眠&#xff0c;改善睡眠质…

NLP_文本张量表示方法_2(代码示例)

目标 了解什么是文本张量表示及其作用.文本张量表示的几种方法及其实现. 1 文本张量表示 将一段文本使用张量进行表示&#xff0c;其中一般将词汇为表示成向量&#xff0c;称作词向量&#xff0c;再由各个词向量按顺序组成矩阵形成文本表示. ["人生", "该&q…

探索安全与灵活性的边界,波卡账户抽象与多签管理的创新之路

相信大家在刚刚进入 web3 的时候都或多或少面临着一个普遍而棘手的问题&#xff0c;私钥的安全管理。私钥一旦丢失或被盗&#xff0c;用户将永久失去对他们加密资产的访问权。此外&#xff0c;随着区块链应用场景的多样化&#xff0c;这种单一模式已经无法满足复杂的交易结构和…

鸿蒙App基础

像素单位 .1、基础单位 为开发者提供4种像素单位&#xff0c;框架采用vp为基准数据单位。 PS&#xff1a;个人建议使用lpx&#xff0c;配置好配置文件&#xff0c;这里就可以按照UI设计稿实际的来&#xff0c;可以更好的实现设计效果 名称描述px屏幕物理像素单位vp屏幕密度相…

Unity 给刚体一个力或速度

创建平面和小球&#xff0c;给力或给速度让其弹起 给小球挂载刚体&#xff08;Rigibdody&#xff09;和脚本 &#xff08;力是累计或者衰减的&#xff0c;直接给速度就是赋值&#xff0c;但如果速度就和力类似了&#xff09; using System.Collections; using System.Collect…

防御保护IPSEC实验

要求&#xff1a;在FW5和FW3之间建立一条IPSEC通道&#xff0c;保证10.0.2.0/24网段可以正常访问到192.168.1.0/24. 因为是双机热备状态则只需要配置FW1主设备。 新建ACL待加密数据流 安全建议&#xff1a; IPSec参数配置 FW3配置如下与FW1类似&#xff1a; FW1中新建安全策略…

根据xlsx文件第一列的网址爬虫

seleniumXpath 在与该ipynb文件同文件下新增一个111.xlsx&#xff0c;第一列放一堆需要爬虫的同样式网页 然后使用seleniumXpath爬虫 from selenium import webdriver from selenium.webdriver.common.by import By import openpyxl import timedef crawl_data(driver, url)…