11.1 网络编程-套接字

news2024/11/5 18:55:11

练习: 使用搭建好的服务器和客户端,实现一个完整的注册,登录功能
                服务器使用链表 + 文件IO的形式去记录账号和密码

代码实现:

服务器端:
#include <myhead.h>
struct Pack{
	char flags;
	char name[20];
	char pswd[20];
};
//创建单链表结构体类型
typedef struct node{
	union{
		int len;
		struct Pack data;
	};
	struct node *next;
}Link,* Plink;
Plink L;
//创建链表表头
Plink create_link(){
	Plink p=(Plink)malloc(sizeof(Link));
	if(p==NULL){
		perror("malloc");
		return NULL;
	}
	p->len=0;
	p->next=NULL;
	return p;
}
//采用尾插法增加注册信息
int insert_tail(Plink L,struct Pack *Pdata){
	//创建新节点
	Plink p=(Plink)malloc(sizeof(Link));
	if(p==NULL){
		perror("malloc");
		return -1;
	}
	p->data=*Pdata;//接收数据
	Plink t=L;
	while(t->next!=NULL){//遍历到尾部
		t=t->next;
	}
	p->next=t->next;
	t->next=p;
	L->len++;
	return 1;
}
//查找登录信息
int research_link(Plink L,struct Pack *Pdata){
	Plink t=L->next;
	while(t!=NULL){
		if(strcmp(t->data.name,Pdata->name)==0&&\
				strcmp(t->data.pswd,Pdata->pswd)==0){
			return 1;
		}
		t=t->next;
	}
	return -1;
}
void handler(int signo){
	if(signo==SIGINT){
		FILE *fp=fopen("./server.txt","a+");
		if(fp==NULL){
			perror("fopen");
			return;
		}
		Plink t=L->next;
		while(t!=NULL){
			fprintf(fp,"%s %s\n",t->data.name,t->data.pswd);
			t=t->next;
		}
		fclose(fp);
		exit(EXIT_SUCCESS);
	}
}
int main(int argc, const char *argv[])
{
	//当服务器断线时,将链表信息存储到文件中保存
	if(signal(SIGINT,handler)==SIG_ERR){
		perror("signal");
		return -1;
	}
	if(argc!=2){
		printf("请输入端口号\n");
		return -1;
	}	
	int port=atoi(argv[1]);//从终端接收端口号
	//创建tcp套接字
	int server=socket(AF_INET,SOCK_STREAM,0);
	//准备一个tcp用的地址信息结构体,用于存放ip和port
	addr_in_t addr={0};
	addr.sin_family=AF_INET;
	addr.sin_port=htons(port);//端口号转为网络字节序
	addr.sin_addr.s_addr=inet_addr("127.0.0.1");//用于测试案例使用
	//使用已经准备好的地址信息结构体,为套接字绑定ip和port
	if(bind(server,(addr_t *)&addr,sizeof(addr))==-1){//因为端口号容易被占用,所以bind会容易出错,需要判断
		perror("bind error");
		return -1;
	}
	//监听
	listen(server,10);
	addr_in_t client_addr={0};
	socklen_t client_len=sizeof(addr);
	int client=accept(server,(addr_t *)&client_addr,&client_len);
	printf("客户端连接成功\n");

	//服务器读取消息
	/*
	 int flags=fcntl(client,F_GETFL);
	 flags=flags|0_NONBLOCK;
	 fcntl(client,F_SETFL,flags);*/

	struct Pack pack={0};
	L=create_link();//创建链表表头
	while(1){
		memset(&pack,0,sizeof(pack));
		int res=read(client,&pack,sizeof(pack));
		if(res==0){	
			printf("客户端断开连接\n");
			close(client);		
			raise(SIGINT);//当客户端断开连接时,向自己进程发送信号
			break;
		}
		if(pack.flags==1){
			//链表增加注册信息采用尾插法
			char flag1;
			if(insert_tail(L,&pack)==1){
				printf("注册信息已加载\n");
				flag1=1;
				write(client,&flag1,1);//往客户端回复已注册成功消息
			}else{
				printf("注册错误,无法加载\n");
				flag1=0;
				write(client,&flag1,1);//往客户端回复注册失败消息
			}
		}else if(pack.flags==2){
			//遍历链表已查找登录信息
			char flag2;
			if(research_link(L,&pack)==1){
				printf("与服务器注册信息匹配\n");
				flag2=1;
				write(client,&flag2,1);//往客户端回复登录成功消息
			}else{
				printf("与服务器注册信息不匹配\n");
				flag2=0;
				write(client,&flag2,1);//往客户端回复登录失败消息
			}
		}

	}
	return 0;
}
客户端端 :
#include <myhead.h> 
struct Pack{
	char flags;
	char name[20];
	char pswd[20];
};
void menu(){
	printf("****用户注册登录功能****\n");
	printf("****1.注册**2.登录******\n");
	printf("*********0.退出*********\n");
}
void logic_user(struct Pack *ps,int client){
	printf("请输入注册姓名:");
	scanf("%s",ps->name);
	printf("请输入注册密码:");
	scanf("%s",ps->pswd);
	write(client,ps,sizeof(struct Pack));
	printf("注册信息已发送\n");
}
void pswd_user(struct Pack *ps,int client){
	printf("请输入登录姓名:");
	scanf("%s",ps->name);
	printf("请输入登录密码:");
	scanf("%s",ps->pswd);
	write(client,ps,sizeof(struct Pack));
	printf("登录信息已发送\n");
}
int main(int argc, const char *argv[])    
{                                         
	if(argc!=2){
		printf("请输入端口号\n");
		return -1;
	}
	int port=atoi(argv[1]);//从终端接收端口号
	//创建tcp套接字
	int client=socket(AF_INET,SOCK_STREAM,0);
	//准备一个tcp用的地址信息结构体,用于存放ip和port
	addr_in_t addr={0};
	addr.sin_family=AF_INET;
	addr.sin_port=htons(port);//端口号转为网络字节序
	addr.sin_addr.s_addr=inet_addr("127.0.0.1");

	//与服务器连接
	if(connect(client,(addr_t *)&addr,sizeof(addr))==-1){
		perror("connect error");
		return -1;
	}
	struct Pack pack={0};
	//向客户端发送消息
	while(1){
		menu();
		char res=0;
		memset(&pack,0,sizeof(pack));
		printf("请输入选项:");
		scanf("%d",&pack.flags);
		switch(pack.flags){
			case 1:
				logic_user(&pack,client);
				read(client,&res,1);//从服务器读取注册完成信号
				if(res==1){
					printf("注册成功\n");
				}else{
					printf("注册失败\n");
				}
				break;
			case 2:
				pswd_user(&pack,client);
				read(client,&res,1);//从服务器读取登录完成信号
				if(res==1){
					printf("登录成功\n");
				}else{
					printf("登录失败\n");
				}
				break;
			case 0:
				exit(EXIT_SUCCESS);
			default:
				printf("输入选项错误,请重新输入\n");
				break;
		}	
	}
	return 0;                             
}          
 实现结果:

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

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

相关文章

基于MATLAB的战术手势识别

手势识别的研究起步于20世纪末&#xff0c;由于计算机技术的发展&#xff0c;特别是近年来虚拟现实技术的发展&#xff0c;手势识别的研究也到达一个新的高度。熵分析法是韩国的李金石、李振恩等人通过从背景复杂的视频数据中分割出人的手势形状&#xff0c;然后计算手型的质心…

面试题整理 1

实际参与的某公司面试&#xff0c;总结了遇到的值得整理记录的面试题。 目录 相对路径 正序判断 倒序判断 输出部门负责人及下级 代码实现 最终效果 科目平均分 SQL筛选 代码实现 分组错误 原因 查看版本 确认模式 设置模式 相遇洞穴 代码实现 方式一&#xf…

mysql查表相关练习

作业要求&#xff1a; 单表练习&#xff1a; 1 . 查询出部门编号为 D2019060011 的所有员工 2 . 所有财务总监的姓名、编号和部门编号。 3 . 找出奖金高于工资的员工。 4 . 找出奖金高于工资 40% 的员工。 5 找出部门编号为 D2019090011 中所有财务总监&#xff0c;和…

基于yolov5的输电线,电缆检测系统,支持图像检测,视频检测和实时摄像检测功能(pytorch框架,python源码)

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; yolov5&#xff0c;输电线(线缆)检测系统&#xff0c;系统既支持图像检测&#xff0c;也支持视频和摄像实时检测【pytorch框架】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的输…

C语言另一种编码方式开发状态机(无switch)

目录 概述 一、开发环境 二、coding 三、运行结果 四、总结 概述 状态机编码思想&#xff0c;在很多领域都随处可见&#xff0c;传统的coding方式使用switch case来实现&#xff0c;状态跳转可读性差&#xff0c;咋们换一种思路来实现状态机开发&#xff0c;该方式 拓展好…

录屏天花板,录课新玩法,人像+一切,PPT/PDF/视频/网页,也可即可录

上新啦 &#x1f4f1;&#x1f4bb; 录屏也能录课的万能神器——超级推荐&#xff01; 你是不是也在找一款能高效录屏、录课、轻松剪辑的小工具&#xff1f;作为一名需要频繁录制屏幕和课程内容的老师&#xff08;或内容创作者&#xff09;&#xff0c;我找到了这个宝藏App&…

vscode php Launch built-in server and debug, PHP内置服务xdebug调试,自定义启动参数配置使用示例

在vscode中&#xff0c;当我们安装了插件 PHP Debug&#xff08;xdebug.php-debug&#xff09;或者 xdebug.php-pack 后 我们通过内置默认的 php xdebug配置启动php项目后&#xff0c;默认情况下我们在vscode中设置断点是不会生效的&#xff0c;因为我们的内置php服务默认启动时…

Linux入门(2)

林纳斯托瓦兹 Linux之父 1. echo echo是向指定文件打印内容 ehco要打印的内容&#xff0c;不加任何操作就默认打印到显示器文件上。 知识点 在Linux下&#xff0c;一切皆文件。 打印到显示器&#xff0c;显示器也是文件。 2.重定向 >重定向操作&#xff0c;>指向的…

Java实战项目-基于 SpringBoot+Vue 的医院管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

代码随想录 | Day36 | 动态规划 :整数拆分不同的二叉搜索树

代码随想录 | Day36 | 动态规划 &#xff1a;整数拆分&不同的二叉搜索树 动态规划应该如何学习&#xff1f;-CSDN博客 动态规划学习&#xff1a; 1.思考回溯法&#xff08;深度优先遍历&#xff09;怎么写 注意要画树形结构图 2.转成记忆化搜索 看哪些地方是重复计算…

【书生.浦语实战营】——入门岛

【书生.浦语实战营】——入门岛_第一关_Linux基础 任务分布1. 本地vscode远程连接并进行端口映射端口映射What——何为端口映射How——怎么进行端口映射 2. Linux基础命令touch &#xff1a;创建文件mkdir &#xff1a;创建目录cd:进入 退出 目录pwd :确定当前所在目录cat:可以…

【Pytorch】Pytorch的安装

目录 一、介绍 1.相关要素 二、NVIDIA显卡安装pytorch 1、官网安装 2、清华源下载 一、介绍 1.相关要素 &#xff08;1&#xff09;nvidia-driver&#xff08;也叫做 cuda driver&#xff09;&#xff1a;英伟达GPU驱动&#xff0c;命令&#xff1a;nvidia-smi &#xf…

HTML+CSS科技感时钟(附源码!!!)

预览效果 源码(直接复制使用) <!DOCTYPE html> <html lang"zh-Hans"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>科技感时钟</…

vue3中跨层传递provide、inject

前置说明 在 Vue 3 中&#xff0c;provide 和 inject 是一对用于跨组件树传递数据的 API。它们允许你在祖先组件中使用 provide 提供数据或服务&#xff0c;然后在后代组件中使用 inject 来获取这些数据或服务。这种方式特别适用于跨多个层级的组件传递数据&#xff0c;而不需要…

Zig 语言通用代码生成器:逻辑,发布冒烟测试版二之二

Zig 语言通用代码生成器&#xff1a;逻辑&#xff0c;发布冒烟测试版二之二 Zig 语言通用代码生成器&#xff1a;逻辑&#xff0c;已发布冒烟测试版二。此版本完善了代码生成物。支持多对多关系。修复了所有单域动词。并有更多缺陷修复。暂时不支持图片类型。暂时不支持日期和…

获取Hive表备注

DESCRIBE EXTENDED 表名;先获取Detailed Table Information这行的data_type字段数据&#xff0c;进行正则匹配&#xff0c;拿到表备注&#xff0c;如下&#xff1a; String str ReUtil.get("parameters:\\{(?!.*?\\().*transient_lastDdlTime.*?comment(.*?)\\}&quo…

前端请求后端接口报错(blocked:mixed-content),以及解决办法

报错原因&#xff1a;被浏览器拦截了&#xff0c;因为接口地址不是https的。 什么是混合内容&#xff08;Mixed Content&#xff09; 混合内容是指在同一页面中同时包含安全&#xff08;HTTPS&#xff09;和非安全&#xff08;HTTP&#xff09;资源的情况。当浏览器试图加载非…

TCP是怎样工作的网络拥塞控制理论和算法部分记录

参考资料 https://github.com/ituring/tcp-book 流量控制、窗口控制和拥塞控制的关系 流量控制、窗口控制和拥塞控制的关系如图所示 窗口控制是上层的概念&#xff0c;核心思路是基于滑动窗口技术传输数据。而确定发送窗口大小的方法有流量控制和拥塞控制两种 流量控制&…

python eval() 怎么用

eval函数的使用方法 函数的作用&#xff1a; 计算指定表达式的值。也就是说它要执行的Python代码只能是单个运算表达式&#xff08;注意eval不支持任意形式的赋值操作&#xff09;&#xff0c;而不能是复杂的代码逻辑&#xff0c;这一点和lambda表达式比较相似。 函数定义&a…

WPF+MVVM案例实战(十二)- 3D数字翻牌计时实现

文章目录 1、运行效果2、功能实现1、文件创建2、控件代码实现3、控件引用与菜单实现1.引用用户控件2.按钮菜单3、计时器界面实现4、源代码获取1、运行效果 3D数字翻牌计时 2、功能实现 1、文件创建 打开项目 Wpf_Examples ,在用户控件 UserControlLib 中创建 NumberFoldi…