网络编程 day 6

news2024/11/26 5:32:00

1、基于UDP聊天室

服务器


#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)
#define IP "127.0.0.1"
#define PORT 6666
//创建链表
Linklistptr list_create();
Linklistptr node_buy(datatype e);
int list_insert_head(Linklistptr L,datatype e);
int chat_login(Linklistptr L,int sfd,msg_t msg,datatype e);
int chat_enter(Linklistptr l,int sfd,msg_t msg,datatype e);
int chat_exit(Linklistptr L,int sfd,msg_t msg,datatype e);
typedef struct sockaddr_in datatype;//类型重命名
//创建信息结构体
typedef struct msg
{
	char type;//操作码 'L'登录 'C'群聊 'Q'退出
	char name[20];
	char text[128];
}msg_t;
//创建链表保存地址信息
typedef struct Node
{
	union
	{
		datatype res_addr;//数据域
		int len;//头结点数据域
	};
	struct Node *next;//指针域
}Node, *Linklistptr;
int main(int argc, const char *argv[])
{
	//创建报式套接字
	int sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket create success sfd=%d\n",sfd);
	//填充接收方的地址信息结构体,给bind函数使用
	datatype sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	//绑定地址信息结构体
	if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success");
	//创建接收地址信息结构体
	datatype cin;
	socklen_t addrlen = sizeof(cin);
	pthread_t tid;
	msg_t msg;
	//创建一个链表
	Linklistptr L = list_create();
	if(NULL == L)
	{
		return -1;
	}
	while(1)
	{
		//主线程负责接收并处理
		if(recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cin, &addrlen) < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		printf("[%s:%d] : %s\n", msg.name, ntohs(cin.sin_port), msg.text);
		switch(msg.type)
		{
		case 'L'://登录
			chat_login(L,sfd,msg,e);
			break;
		case 'C'://群聊
			chat_enter(L,sfd,msg,e);
			break;
		case 'Q'://退出
			chat_exit(L,sfd,msg,e);
			break;
		default :
			printf("输入错误\n");
			break;
		}
		info.sfd=sfd;
		info.sin=sin;
		//分支线程只负责发送系统信息
		if(pthread_create(&tid, NULL, task,(void*)&info) != 0)
		{
			fprintf(stderr, "pthread_create  failed__%d__\n",__LINE__);
			return -1;
		}
		pthread_detach(tid);
	}
	//关闭文件描述符
	if(close(sfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	return 0;
}
void *task(void *arg)
{
	int sfd = ((struct Climsg*)arg)->sfd;
	datatype sin = ((struct Climsg*)arg)->sin;
	msg_t msg;
	msg.type = 'C';
 
	while(1)
	{
 
		//从终端获取消息文本
		fgets(msg.text, sizeof(msg.text), stdin);
		msg.text[strlen(msg.text)-1] = '\0';
		//将信息包名定为服务器
		strcpy(msg.name,"servce");
		if(sendto(sfd , &msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
		}
	}
	close(sfd);
	pthread_exit(NULL);
}
//创建链表
Linklistptr list_create()
{
	//从堆区申请一个头结点类型
	Linklistptr L = (Linklistptr)malloc(sizeof(Node));
	if(NULL == L)
	{
		printf("创建失败\n");
		return NULL;
	}
	//创建成功后,对节点进行初始化工作
	L->len = 0;
	L->next = NULL;
	return L;
}
//申请节点封装地址信息
Linklistptr node_buy(datatype e)
{
	//在堆区申请节点
	Linklistptr p = (Linklistptr)malloc(sizeof(Node));
	if(NULL == p)
	{
		printf("申请失败]n");
		return NULL;
	}
	//节点申请成功,封装数据
	p->res_addr = e;
	p->next = NULL;
	return p;
}
//头插
int list_insert_head(Linklistptr L,datatype e)
{
	//判断逻辑
	if(NULL == L)
	{
		printf("所给链表不合法\n");
		return -1;
	}
	//调用节点封装数据
	
	Linklistptr p = node_buy(e);
	if(NULL == p)
	{
		return -1;
	}
	//头插
	p->next = L->next;
	L->next = p;
	//表长变化
	L->len++;
	return 0;
}
int chat_login(Linklistptr L,int sfd,msg_t msg,datatype e)
{
	Linklistptr p=L;//定义一个遍历指针
	while(p->next!=NULL)
	{
		p=p->next;
		if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr *)&(p->res_addr),sizeof(p->res_addr))<0)
		{
			ERR_MSG("sendto");
			return -1;
		}
	}
	//头插,将自己的地址存入链表中
	list_insert_head(L,e);
	return 0;
}
//群聊
int chat_enter(Linklistptr l,int sfd,msg_t msg,datatype e)
{
	//定义一个遍历指针
	Linklistptr p=L;
	while(p->next!=NULL)
	{
		p=p->next;
		//判断链表客户端信息
		if(memcmp(&(p->res_addr),&e,sizeof(e))==0)
		{
			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&(p->res_addr),sizeof(p->res_addr))<0)
			{
				ERR_MSG("sendto");
				return -1;
			}
		}
	}
	return 0;
}
//退出
int chat_exit(Linklistptr L,int sfd,msg_t msg,datatype e)
{
	Linklistptr p=L;
	while(p->next!=NULL)
	{	
		p=p->next;
		//判断链表客户端信息
		if(memcmp(&(p->res_addr),&e,sizeof(e))==0)
		{
			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&(p->res_addr),sizeof(p->res_addr))<0)
			{
				ERR_MSG("sendto");
				return -1;
			}
		}
		else//此时当前节点的下一个节点保存的就是要退出的成员的信息
		{
			Linklistptr q=p->next;
			if(sendto(sfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&(q->resin), sizeof(q->resin)) < 0)
			{
				ERR_MSG("sendto");
				return -1;
			}
			p->next=q->next;
			free(q);
			q=NULL;
		}
	}
	return 0;
}

客户端

#include <myhead.h>
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)
#define IP "127.0.0.1"
#define PORT 4399
typedef struct sockaddr_in datatype;//类型重命名
//创建信息结构体
typedef struct msg
{
	char type;//操作码 'L'登录 'C'群聊 'Q'退出
	char name[20];
	char text[128];
}msg_t;
 
struct Climsg
{
	int cfd;
	datatype cin;
	msg_t msg;
};
void *task(void *arg);
int main(int argc, const char *argv[])
{
		//创建报式套接字
	int cfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(cfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket create success cfd=%d\n",cfd);
	//填充接收方的地址信息结构体,给sendto函数使用
	datatype sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	//创建接收地址信息结构体
	datatype cin;
	socklen_t c_addrlen = sizeof(cin);	
	pthread_t tid;
	msg_t msg;
	memset(&msg, 0, sizeof(msg_t));
	struct Climsg info;
	printf("请输入登录名:");
	fgets(msg.name, sizeof(msg.name), stdin);
	msg.name[strlen(msg.name)-1] = '\0';	
	msg_t msg1=msg;
	msg.type = 'L';
	strcpy(msg.text,"已进入群聊");
	//发送登录请求包
	if(sendto(cfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("sendto");
		return -1;
	}
	printf("登陆成功\n");
	info.cfd = cfd;
	info.cin = sin;
	info.msg = msg;	
	while(1)
	{
		
		memset(&msg, 0, sizeof(msg));
		if(recvfrom(cfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&cin, &c_addrlen) < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		if(strcmp(msg.name, msg1.name) == 0)
		{
			break;
		}
 
		printf("[%s] : %s\n", msg.name, msg.text);
 
 
		if(pthread_create(&tid, NULL, task, (void *)&info) != 0)
		{
			ERR_MSG("pthread_create");
			return -1;
		}
	
		//将分支线程设置为分离态
		pthread_detach(tid);
		}
 
	//关闭套接字描述符
	close(cfd);
	return 0;
}
//线程体函数
void *task(void *arg)
{
 
	int cfd = ((struct Climsg*)arg)->cfd;
	datatype sin = ((struct Climsg*)arg)->cin;
	msg_t msg = ((struct Climsg*)arg)->msg;
 
	while(1)
	{
		//清空文本内容
		bzero(msg.text, sizeof(msg.text));
		//从终端获取数据
		fgets(msg.text, sizeof(msg.text), stdin);
		msg.text[strlen(msg.text)-1] = '\0';
 
		msg.type = 'C';
		if(strcmp(msg.text,"quit") == 0)
		{
			msg.type = 'Q';
			strcpy(msg.text, "已下线");
		}
		if(sendto(cfd, &msg, sizeof(msg_t), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
		}
		if(strcmp(msg.text, "已下线") == 0)
		{
			break;
		}
	}
	close(cfd);
	pthread_exit(NULL);
}

2、思维导图

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

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

相关文章

You must install at least one postgresql-client-<version> package

使用主机上的映射端口来连接到 PostgreSQL 数据库。例如&#xff0c;使用以下命令连接到数据库&#xff1a; psql -h localhost -p 5432 -U postgres出现下面的问题&#xff1a; 分析&#xff1a; 如果您在运行 psql 命令时遇到错误消息 You must install at least one pos…

flex布局轻而易举实现页面布局;超详细解析轻松掌握

我们曾如此渴望命运的波澜&#xff0c;到最后才发现&#xff0c;人生最曼妙的风景&#xff0c;竟是内心的淡定和从容。我们曾如此期盼外界的认可&#xff0c;到最后才知道&#xff0c;世界是自己的&#xff0c;与他人毫无关系。——杨绛 开始 痛点 网页布局&#xff08;layout…

数据分析因子评分学习

当多个因素影响一个结果时&#xff0c;我们需要综合考虑这些因素分别对结果德影响。因子评分就是用于比较其对结果德影响程度。 文章目录 前言一、案例背景二、解决方案&#xff08;一&#xff09;分析思路&#xff08;二&#xff09;剔除无关数据&#xff08;三&#xff09;求…

role、user、schema在Oracle、MySQL、PostgreSQL的区别

0.先上结论 数据库逻辑可以细分为&#xff1a;角色、用户、数据库、模式PostgreSQL和MySQL合并了角色和用户&#xff0c;MySQL还合并了数据库、模式Oracle合并了用户、数据库、模式 1.图 1.1.架构 1.2.用户和角色 1.2.1.PostgreSQL 1.2.2.MySQL 1.2.3.Oracle 参考文章 数据…

安卓绘制原理概览

绘制原理 Android 程序员都知道 Android 的绘制流程分为 Measure、Layout、Draw 三步骤&#xff0c;其中 Measure 负责测量 View 的大小Layout 负责确定 View 的位置Draw 负责将 View 画在屏幕上 由 ViewRootImpl 实现的 performTraversal 方法是 Measure、layout、draw 的真正…

教育培训小程序的设计与功能解析

随着互联网的发展&#xff0c;线上教育逐渐成为一种趋势&#xff0c;越来越多的人开始选择在线学习。而搭建一个适合自己的线上教育小程序&#xff0c;可以为教育机构或个人提供更好的教学和学习体验。在本文中&#xff0c;我们将介绍如何通过一个第三方制作平台来搭建在线教育…

【Maven教程】(五)仓库:解析Maven仓库—布局、分类和配置,远程仓库的认证与部署,快照版本,依赖解析机制,镜像和搜索服务 ~

Maven 仓库 1️⃣ 什么是Maven仓库2️⃣ 仓库的布局3️⃣ 仓库的分类3.1 本地仓库3.2 远程仓库3.3 中央仓库3.4 私服 4️⃣ 远程仓库的配置4.1 远程仓库的认证4.2 部署至远程仓库 5️⃣ 快照版本6️⃣ 从仓库解析依赖的机制7️⃣ 镜像8️⃣ 仓库搜索服务8.1 Sonatype Nexus8.2…

大白菜清理电脑密码教程

首先安装大白菜&#xff1a; 插入u盘一键制作启动盘 制作成功&#xff0c;重启进入u盘启动模式

监控平台 - zabbix

目录 一、概述 二、搭建 一、概述 1. zabbix程序结构 zabbix-server&#xff1a;用于数据处理及写入到数据库 zabbix-agent&#xff1a;用于获取被监控端的性能检测数据 zabbix-web&#xff1a;用于数据的展示及远程操控 数据库&#xff1a;用于存储监控数据 zabbix-pr…

夜神模拟器进行APP抓包

夜神模拟器进行APP抓包 1、fiddler安装和配置1.1配置fiddler允许监听到https1.2配置fiddler允许远程连接1.3重启Fiddler&#xff08;配置完成后需要重启才能生效&#xff09; 2、安装夜神模拟器&#xff0c;并配置代理2.1打开模拟器wifi&#xff0c;修改网络代理2.2打开内置浏览…

基于深度学习网络的人员吸烟行为检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 clc; clear; close all; warning off; addpath(genpath(pwd)); rng(default)load FRCNN.mat I…

忧郁菇的介绍

前言 此文章为“植物大战僵尸”专栏中的第006刊&#xff08;2023年9月五刊&#xff09;。 无名版中有很多紫卡植物&#xff0c;分别是忧郁菇、玉米加农炮、猫尾草、机枪射手、地刺王、冰西瓜投手、双子向日葵、吸金菇。 提示&#xff1a; 1.用于无名版&#xff1b; 2.用于…

(数字图像处理MATLAB+Python)第十一章图像描述与分析-第七、八节:纹理描述和其他描述

文章目录 一&#xff1a;纹理描述&#xff08;1&#xff09;联合概率矩阵法A&#xff1a;定义B&#xff1a;基于联合概率矩阵的特征C&#xff1a;程序 &#xff08;2&#xff09;灰度差分统计法A&#xff1a;定义B&#xff1a;描述图像特征的参数 &#xff08;3&#xff09;行程…

(16)线程的实例认识:Await,Async,ConfigureAwait

继续(15)的例子 一、ConfigureAwait()的作用 private async void BtnAsync_Click(object sender, EventArgs e)//异步{Stopwatch sw Stopwatch.StartNew();TxtInfo.Clear();AppendLine("异步检索开始...");AppendLine($"当前线程Id:{Environment.CurrentManage…

Golang复习

文章目录 golang的特点golang数据类型基本数据类型&#xff08;值类型&#xff09;引用数据类型 make和newmakenew 浅拷贝&#xff0c;深拷贝深拷贝&#xff1a;实现深拷贝的方式&#xff1a;浅拷贝&#xff1a;实现浅拷贝的方式 接口接口是什么 某种类型可以比较吗channel数据…

flutter 里面自定义appbar

众所周知&#xff0c;fluuter里面的appbar 包含title&#xff0c; leading&#xff0c;action, bottom 如果我想在appbar里面自定一些内容&#xff0c;他会默认继承appbar的高度&#xff0c;且位置也没法自定义&#xff0c;如下图 这个时候我该怎么办? 在appbar里面将下面的内…

【JVM】对象死亡判断

文章目录 简述引用计数算法可达性分析算法4种对象引用finalize()方法回收方法区 简述 在堆里面存放着Java世界中几乎所有的对象实例&#xff0c;垃圾收集器在对堆进行回收前&#xff0c;第一件事情就是要确定这些对象之中哪些还“存活”着&#xff0c;哪些已经“死去”&#x…

(17)线程的实例认识:wait,waitany,waitall,及经典死锁问题

一、文件构成 1、界面&#xff1a;一个textbox,四个button。 2、程序&#xff1a;前面(15)的book类与data类 private void AppendLine(string s){txtInfo.AppendText(string.IsNullOrEmpty(txtInfo.Text) ? s : $"{Environment.NewLine}{s}");…

Redis 7 第八讲 集群模式(cluster)架构篇

集群架构 Redis 集群架构图 集群定义 Redis 集群是一个提供在多个Redis节点间共享数据的程序集;Redis集群可以支持多个master 应用场景 Redis集群支持多个master,每个master又可以挂载多个slave读写分离支持数据的高可用支持海量数据的读写存储操作集群自带Sentinel的故障…

看懂UML类图

UML 统一建模语言(Unified Modeling Language&#xff0c;UML)是一种为面向对象系统的产品进行说明、可视化和编制文档的一种标准语言&#xff0c;是非专利的第三代建模和规约语言。UML是面向对象设计的建模工具&#xff0c;独立于任何具体程序设计语言。 类的表示 首先看那个…