基于UDP实现的网络聊天室

服务器:

#include <myhead.h>
struct msg
{
	char type;
	char name[20];
	char text[1024];
};

int main(int argc, const char *argv[])
{
	if(argc!=3)
	{
		printf("input error\n");
		printf("./a.out IP地址 端口号\n");
		return -1;
	}

    //1、创建用于通信的套接字
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd == -1)
    {
        perror("socket error");
        return -1;
    }

 //将端口号快速重用
        int reuse = 1;
        if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1)
        {   
            perror("setsockopt error");
            return -1;                                                                     
        }  

    //2、绑定IP地址和端口号
    //2.1填充地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;          //地址族
	short port=(short)atoi(argv[2]);
    sin.sin_port = htons(port);        //端口号
    sin.sin_addr.s_addr = inet_addr(argv[1]);   //IP地址


    //2,2绑定
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }
    printf("bind success\n");

	 //定义容器接收对端地址信息结构体
    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);

	//定义存储客户端地址信息结构体信息
	struct sockaddr_in scin[1024];
	for(int i=0;i<1024;i++)
	{
		scin[i].sin_family=AF_INET;
	}

	 //1、创建文件描述符容器
    fd_set readfds, tempfds;
    //2、清空容器内容
    FD_ZERO(&readfds);
    //3、将sfd和0号文件描述符放入容器中
    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);

	//定义结构体变量,用于接收和发送,和客户端进行通信
	struct msg send;
	struct msg in;
	
	int res;
	char buf[128]="";
	char address[128]="";
	int n=0;

	while(1)
	{
		bzero(buf,sizeof(buf));
		bzero(address,sizeof(address));
		tempfds = readfds;      //将要检测的容器复制保存一份
	    res = select(sfd+1, &tempfds, NULL, NULL, NULL);  //阻塞等待集合中事件产生
		if(res == -1)
		{
			perror("select error");
			return -1;
		}else if(res == 0)
		{
			printf("time out\n");
			return -1;
		}

		//接收从客户端发来的消息
		if(FD_ISSET(sfd,&tempfds))
		{
			res=recvfrom(sfd,&in,sizeof(in),0,(struct sockaddr*)&cin,&socklen);
			if(res==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			if(in.type=='L')
			{
				scin[n]=cin;
				n++;
			//	sprintf(buf,"---%s 已上线---",in.name);
				sprintf(address,"---%s[%s:%d]登录成功---",in.name,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
				printf("%s\n",address);
				for(int i=0;i<n;i++)
				{
					if(scin[i].sin_port==cin.sin_port)
					{
						continue;
					}
					sendto(sfd,&in,sizeof(in),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));
				}
				bzero(address,sizeof(address));
			}
			if(in.type=='C')
			{
				sprintf(address,"---%s[%s:%d]chat成功---",in.name,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
				printf("%s\n",address);

				//群聊
				send.type=in.type;
				strcpy(send.name,in.name);
				strcpy(send.text,in.text);
				for(int i=0;i<n;i++)
				{
					if(scin[i].sin_port==cin.sin_port)
					{
						continue;
					}
					sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));


				}
			}
			if(in.type=='Q')
			{
				//下线
				send.type=in.type;
				strcpy(send.name,in.name);
				strcpy(send.text,in.text);

				for(int i=0;i<n;i++)
				{
					bzero(buf,sizeof(buf));
					sprintf(buf,"---%s已下线---\n",send.name);
					printf("%s\n",buf);
					//删除用户
					if(scin[i].sin_port==cin.sin_port)
					{
						int t=i;
						for(int j=i;j<=n;j++)
						{
							scin[t]=scin[t+1];
							t++;
						}
					}
					n--;
					sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));
				}
			
			}
		}
		if(FD_ISSET(0,&tempfds))
		{
			//用于接收系统的消息
			bzero(&send,sizeof(send));
			strcpy(send.name,"系统消息");
			fgets(send.text,sizeof(send.text),stdin);
			send.text[strlen(send.text)-1]=0;
			send.type='C';
			for(int i=0;i<=n;i++)
			{
				sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));
			}
		}


	}

	close(sfd);



	return 0;
}

客户端:

#include <myhead.h>
struct msg
{
	char type;
	char name[20];
	char text[1024];
};

int main(int argc, const char *argv[])
{
	if(argc!=3)
	{
		printf("input error\n");
		printf("usage:./a.out IP地址 端口号\n");
		return -1;
	}

	//1、创建用于通信的套接字
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd == -1)
    {
        perror("socket error");
        return -1;
    }

	//2、绑定IP地址和端口号
    //2.1填充服务器端地址信息结构体
    struct sockaddr_in sin;
	short port=(short)atoi(argv[2]);
    sin.sin_family = AF_INET;          //地址族
    sin.sin_port = htons(port);        //端口号
    sin.sin_addr.s_addr = inet_addr(argv[1]);   //IP地址
	
	//定义容器接收服务器端地址信息结构体
    socklen_t socklen = sizeof(sin);



	//定义结构体变量,用于发送和接收
	struct msg send;
	struct msg in;
	printf("请输入用户名>>>");
	fgets(send.name,sizeof(send.name),stdin);
	send.name[strlen(send.name)-1]=0;
	send.type='L';
	//将登录的用户名发送给服务器
	sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&sin,socklen);
	
    //1、创建文件描述符容器
    fd_set readfds, tempfds;
    //2、清空容器内容
    FD_ZERO(&readfds);
    //3、将sfd和0号文件描述符放入容器中
    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);

	int res1;
	char buf[128]="";

	while(1)
	{
		 tempfds = readfds;      //将要检测的容器复制保存一份
        int res = select(sfd+1, &tempfds, NULL, NULL, NULL);  //阻塞等待集合中事件产生
        if(res == -1)
        {
            perror("select error");
            return -1;
        }else if(res == 0)
        {
            printf("time out\n");
            return -1;
        }

		//接收从服务器发来的消息
		if(FD_ISSET(sfd,&tempfds))
		{
			res1=recvfrom(sfd,&in,sizeof(in),0,(struct sockaddr*)&sin,&socklen);
			if(res1==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			if(in.type=='L')
			{
				printf("---%s上线了---\n",in.name);
			}
			if(in.type=='C')
			{
				printf("%s: %s\n",in.name,in.text);
			}
			if(in.type=='Q')
			{
				printf("---%s已下线---\n",in.name);
			}

		}
		//如果程序执行到此,说明检测的集合中有事件产生
        if(FD_ISSET(0, &tempfds))       //表示sfd触发了事件
		{
			//判断是群聊还是退出
			bzero(send.text,sizeof(send.text));
			fgets(send.text,sizeof(send.text),stdin);
			send.text[strlen(send.text)-1]=0;
			if(strcmp(send.text,"quit")==0)
			{
				send.type='Q';
				sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&sin,socklen);
				break;
			}else
			{
				send.type='C';
				sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&sin,socklen);
			}
		}

	}
	close(sfd);
	return 0;
}

运行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

美国国家安全局(NSA)和美国政府将Delphi/Object Pascal列为推荐政府机构和企业使用的内存安全编程语言

上周&#xff0c;美国政府发布了《回到构建块&#xff1a;通往安全和可衡量软件的道路》的报告。本报告是美国网络安全战略的一部分&#xff0c;重点关注多个领域&#xff0c;包括内存安全漏洞和质量指标。 许多在线杂志都对这份报告发表了评论&#xff0c;这些杂志强调了对 C…

css clip-path polygon属性实现直角梯形

2024.3.8今天我学习了如何用css实现直角梯形的效果&#xff0c; 效果&#xff1a; 具体实现原理&#xff1a; 一、需要三个div&#xff1a; 外面一个大的div&#xff0c;里面左右两个小的div 我们需要先把第一个div变成直角梯形&#xff1a; 大概是这样&#xff0c;设置好之…

web服务之虚拟主机功能

华子目录 概述基于IP地址的虚拟原理实验 基于不同端口号的虚拟主机原理实验 基于域名的虚拟主机原理域名解析实验 概述 如果每台运行 Linux 系统的服务器上只能运行一个网站&#xff0c;那么人气低、流量小的草根站长就要被迫承担着高昂的服务器租赁费用了&#xff0c;这显然也…

项目申报书引言部分

文献引用方式&#xff1a; 张三 等&#xff0c;2024&#xff1b; Zhang S et al.,2015&#xff1b; &#xff08;中文是中文逗号&#xff0c;英文是英文逗号&#xff09;

【你也能从零基础学会网站开发】Web建站之HTML+CSS入门篇 CSS常用属性

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 CSS常用属性…

ARM64汇编04 - 条件码

关于分支控制与条件码的作用可以去看 《CSAPP》的第 3.6 节&#xff0c;讲的非常清楚&#xff0c;建议看看&#xff0c;这里就不重复了。 我们直接使用一个例子来简单理解汇编是如何实现分支控制的&#xff1a; #include <stdio.h> #include <stdlib.h> #include…

【MATLAB第98期】基于MATLAB的MonteCarlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】

【MATLAB第98期】基于MATLAB的Monte Carlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】 PS:因内容涉及较多&#xff0c;所以一时半会更新不完 后期会将相关原理&#xff0c;以及多种功能详细介绍。 麻烦点赞收藏&#xff0c;及时获取更新消息。 引言 在…

Easticsearch性能优化之索引优化

Easticsearch性能优化之索引优化 一、合理的索引设计二、合理的分片和副本三、合理的索引设置 对于性能优化&#xff0c;Elasticsearch&#xff08;以下简称ES&#xff09;的索引优化是提高性能的关键因素之一。合理的设计索引&#xff0c;合理的分片和副本以及合理的缓存设置等…

VSCode报错:/bin/sh: python: command not found

背景 以前都是直接用txt写python&#xff0c;然后直接命令行运行。 这次涉及的代码较多&#xff0c;决定用编译器。 写好的一段python点击运行报错&#xff01; 问题描述 因为我本地安装的是python3&#xff0c;但是vscode用的是另一个路径的python&#xff0c;所以找不到 解…

[React 进阶系列] React Context 案例学习:使用 TS 及 HOC 封装 Context

[React 进阶系列] React Context 案例学习&#xff1a;使用 TS 及 HOC 封装 Context 具体 context 的实现在这里&#xff1a;[React 进阶系列] React Context 案例学习&#xff1a;子组件内更新父组件的状态。 根据项目经验是这样的&#xff0c;自从换了 TS 之后&#xff0c;…

光谱整形1

华为张德江&#xff1a;下一代光传送网将走向400G80波WDM系统_通信世界网 (cww.net.cn) 张德江指出&#xff0c;400G WDM系统具有三大基本特征&#xff1a;支持400G80波&#xff0c;单纤32T超大容量&#xff0c;传输距离与100G相当&#xff1b;支持32维以上的光交叉&#xff1…

微前端之使用无界创建一个微前端项目

wujie 使用手册 使用简介 主应用配置 安装 wujie依赖main.js配置 是否开启预加载 生命周期函数 – lifecycle.js配置 子应用配置 跨域设置运行模式 生命周期改造 在主应用中&#xff0c;使用wujie&#xff0c;将子应用引入到主应用中去 wujie 使用手册 wujie 是一个基于 Web…

Linux环境下使用interrupt方式操作UART

目录 概述 1 Linux环境下UART设备 2 轮询方式操作UART功能实现 2.1 打开串口函数&#xff1a;usr_serial_open 2.2 关闭串口函数&#xff1a; usr_serial_close 2.3 发送数据函数&#xff1a; usr_serial_sendbytes 2.4 接收数据函数&#xff1a; usr_serial_readinterr…

Android 性能优化--APK加固(2)加密

文章目录 字符串加密图片加密如何避免应用被重新签名分发APK 加壳的方案简析DEX加密原理及实现 本文首发地址&#xff1a;https://h89.cn/archives/212.html 最新更新地址&#xff1a;https://gitee.com/chenjim/chenjimblog 通过 前文 介绍&#xff0c;我们知晓了如何使用代码…

前端网络请求异步处理——Promise使用记录

Promise是ES6中新增的一个处理复杂异步请求的工具&#xff0c;其主要形式为&#xff1a; const baseUrl http://localhost:80 export const $request (param {}) > {console.log(请求参数, param)return new Promise((resolve, reject) > {wx.request({url: baseUrl …

SpringMVC拦截器和过滤器执行顺序及区别

拦截器&#xff08;Inteceptor&#xff09;和过滤器&#xff08;Filter&#xff09;执行顺序&#xff1f; 拦截器和过滤器区别&#xff1f; 1、拦截次数不同&#xff1a; 过滤器&#xff1a;一次请求只能被一个过滤器拦截一次&#xff0c;它们按照在web.xml中的声明顺序依次执…

Python Web开发记录 Day7:Django(Web框架) part 1

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 七、Django1、快速了解Django①概述②核心功能③…

css flex 布局换行

默认使用display: flex;是不换行的&#xff0c;只需要加上flex-wrap: wrap;就行了&#xff0c;效果图 .app-center {display: flex;flex-wrap: wrap;justify-content:flex-start; } 通过上面我们发现虽然时间换行了&#xff0c;但是每行的边距不一样 加上这个就行了&#xff…

华为配置DHCP Snooping防止DHCP Server仿冒者攻击示例

配置DHCP Snooping防止DHCP Server仿冒者攻击示例 组网图形 图1 配置DHCP Snooping防止DHCP Server仿冒者攻击组网图 DHCP Snooping简介配置注意事项组网需求配置思路操作步骤配置文件 DHCP Snooping简介 在一次DHCP客户端动态获取IP地址的过程中&#xff0c;DHCP Snoopi…

开源分子对接程序rDock使用方法(1)-Docking in 3 steps

欢迎浏览我的CSND博客&#xff01; Blockbuater_drug …点击进入 文章目录 前言一、Docking in 3 steps 标准对接rDock 的基本对接步骤及注意事项 二、 三步对接案例Step 1. 结构文件准备Step 2. 产生对接位点Step 3. 运行分子对接3.1 检查输入文件3.2 测试-只进行打分3.3 运行…