11.1 网络编程-套接字

练习: 使用搭建好的服务器和客户端,实现一个完整的注册,登录功能
                服务器使用链表 + 文件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;                             
}          
 实现结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值