目录
项目要求:
考虑点:
实现过程
所用知识点
最终效果如下:
项目要求:
考虑点:
服务器端用select监听多个客户端,考虑点在于,公司内部的系统管理系统,不会有太多人每天都登陆,监听1024-4个客户端是够用的,(0,1,2,3被占用)
select会把所有建立连接的套接字都放到一个链表里,当某个套接字(文件描述符)有事件就会留在这个集合中,进行一步步的处理,代码在下面---->
实现过程
1.服务器端先创建员工数据库,包含两张表(员工表,历史记录表)
2.要建立通信
3.使用io多路复用(select)实现客户端服务器的交互传输(登陆,添加,删除.....)
将每个功能函数进行封装,并且每个功能函数中都要调用历史记录的插入函数,这样历史记录表中才能有数据。
所用知识点
1.tcp/ip 通信的建立过程(套接字,绑定,监听,收发数据)
2.并发服务器---多种方式可实现(多进程,多线程,io多路复用)
3.数据库接口的使用
4.函数封装,结构体传参。代码编写逻辑,每一个功能分步实现。
最终效果如下:
登陆界面:
修改:
删除:
添加
查询历史记录
总结
代码编写过程中遇到不少bug,一开始的思路和扎实的基础相当重要,
遇到错误首先要针对性排查,知道错因
编写代码要条例清晰,一个功能一个功能的实现,每实现一个测试一下,理清思路很重要,毕竟代码相当抽象。
#include <stdio.h>
#include "yg.h"
int updateMaxfd(int maxfd, fd_set readfds);
sqlite3 *create_sqlitedb(void);
int do_login(int sfd, MSG *msg, sqlite3 *db); // 登陆
int ser_add(int sfd, MSG *msgser, sqlite3 *db);
int select_by_name(int sensfd, MSG *msgser, sqlite3 *db);
int select_all(int sensfd, MSG *msgser, sqlite3 *db);
int Change_ser(int sensfd, MSG *msg_ser, sqlite3 *db);
int delete_ser(int sensfd, MSG *msgser, sqlite3 *db);
int history_ser(int sensfd, MSG *msgser, sqlite3 *db);
void insert_history(sqlite3 *db,char *name,char *opera);
//接收发送
void send_recv(int sfd, MSG *msg);
int main(int argc, char const *argv[])
{
// 打开数据库,创建2张表
sqlite3 *db;
db = create_sqlitedb();
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0)
{
ERR("socket failed");
return -1;
}
printf("创建套接字成功\n");
int reuse = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR("setsockopt failed");
return -1;
}
struct sockaddr_in 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("bind failed");
return -1;
}
printf("绑定成功\n");
if (listen(sfd, 10) < 0)
{
ERR("listen");
return -1;
}
printf("监听设置成功\n");
fd_set readfds, tempfds;
// 清空读集合
FD_ZERO(&readfds);
FD_ZERO(&tempfds);
// 把需要的文件描述符放到读集合中
FD_SET(0, &readfds);
FD_SET(sfd, &readfds);
int maxfd = sfd;
int se; // 接收select函数返回值
char buf[128] = ""; // 存放客户端发来的信息
MSG msgcli; // 结构体存放客户端发来的消息
ssize_t res = 0;
int newfd = 0;
// 定义数组存储客户端的地址信息结构体,客户端不会再有012sfd4个去掉
struct sockaddr_in cinaddr[1024 - 4];
struct sockaddr_in cin; // cin存放客户端的IP端口
socklen_t cinlen = sizeof(cin);
int i = 0;
while (1)
{
tempfds = readfds;
se = select(maxfd + 1, &tempfds, NULL, NULL, NULL);
if (se < 0)
{
ERR("select failed");
return -1;
}
else if (0 == se)
{
printf("time out\n");
break;
}
// 此时有事件发生,判断哪个文件描述符有事件触发
for (i = 0; i <= maxfd && se != 0; i++)
{
// 对监听到的文件描述符做判断
if (FD_ISSET(i, &tempfds))
{
// 该文件描述符在集合中,执行操作
se--; // 当se==0就绪个数处理完成
if (0 == i)
{
// 向客户端发送消息
int sendfd;
bzero(&msg, sizeof(MSG));
res = scanf("%d %s", &sendfd, buf);
while (getchar() != 10)
;
printf("sendfd=%d %s\n", sendfd, buf);
if (res != 2)
{
fprintf(stderr, "请输入正确的格式:fd string\n");
continue;
}
if (sendfd <= 3 || FD_ISSET(sendfd, &readfds) == 0)
{
fprintf(stderr, "输入文件描述符有误%d\n", sendfd);
continue;
}
if (send(sendfd, buf, sizeof(buf), 0) < 0)
{
ERR("send");
return -1;
}
printf("发送成功\n");
}
else if (sfd == i)
{
// 客户端连接
newfd = accept(sfd, (struct sockaddr *)&cin, &cinlen);
if (newfd < 0)
{
ERR("accept");
return -1;
}
// 连接成功
printf("[%s:%d] newfd=%d客户端连接成功\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
// 将客户端的地址信息结构体转存到数组中
cinaddr[newfd - 4] = cin;
// 将新连接的newfd添加到readfds集合中
FD_SET(newfd, &readfds);
// 更新maxfd
maxfd = maxfd > newfd ? maxfd : newfd;
}
else
{
// 客户端交互
bzero(msg, sizeof(MSG));
// i连接成功的文件描述符
// 接收到的消息放到msgcli结构体中
// printf("yes\n");
res = recv(i, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
return -1;
}
else if (0 == res)
{
fprintf(stderr, "[%s:%d] newfd=%d客户端关闭\n", inet_ntoa(cinaddr[i - 4].sin_addr), ntohs(cinaddr[i - 4].sin_port), i);
printf("%s\n", buf);
close(i); // 关闭不需要的文件描述符
FD_CLR(i, &readfds);
maxfd = updateMaxfd(maxfd, readfds);
}
else
{
// res>0收到客户端的消息----做相应处理
fprintf(stderr, "[%s:%d] newfd=%d客户\n", inet_ntoa(cinaddr[i - 4].sin_addr), ntohs(cinaddr[i - 4].sin_port), i);
char type = msg->msgtype;
switch (type)
{
case 'L': // 登陆
do_login(i, msg, db);
break;
case 'u': // 登陆
printf("%c\n", msg->msgtype);
if(msg->info.usertype=='u')
{
do_login(i, msg, db);
}
break;
case 'A':
ser_add(i, msg, db);
break;
case 'F':
//人名查找
select_by_name(i,msg,db);
break;
case 's':
select_all(i,msg,db);
break;
case 'C':
//修改
Change_ser(i,msg,db);
break;
case 'D':
//删除
delete_ser(i,msg,db);
break;
case 'H':
history_ser(i,msg,db);
break;
}
}
}
}
}
}
close(sfd);
return 0;
}
// 查询历史记录
int history_ser(int sensfd, MSG *msgser, sqlite3 *db)
{
char sql[] = "select * from history"; // 存放数据库查询语句
char **pres = NULL; // 存放数据库查询到的首地址
int row,column,i,j,k=0;
insert_history(db,msgser->info.name,sql);
bzero(msgser->recvmsg,sizeof(msgser->recvmsg));
if (sqlite3_get_table(db, sql, &pres, &row, &column, NULL) != 0)
{
//用户名密码错误
ERR_sqlite3(db);
return -1;
}else if(0==row)
{ //
sprintf(msgser->recvmsg,"没有记录");
exit -1;
}else{
for(i=0;i<=row;i++)
{
for(j=0;j<column;j++)
{
sprintf(msgser->recvmsg+strlen(msgser->recvmsg),"%s\t",pres[k++]);
}
strcat(msgser->recvmsg,"\n");
}
}
if(send(sensfd, msgser, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
printf("返回历史记录\n");
printf("%s\n",msg->recvmsg);
return 0;
}
//向历史记录表插入数据
void insert_history(sqlite3 *db,char *name,char *opera)
{
char sql[256]="";
char* errmsg = NULL;
char l_time[32] = "";
time_t t = time(NULL);
//info指向获取当前时间的地址
struct tm* info = localtime(&t);
sprintf(l_time, "%d-%02d-%02d %02d:%02d",info->tm_year+1900, info->tm_mon+1, info->tm_mday,\
info->tm_hour, info->tm_min);
bzero(sql, sizeof(sql));
sprintf(sql, "insert into history values(\"%s\", \"%s\", \"%s\")", \
l_time,name,opera);
//printf("sql = %s %d\n", sql, __LINE__);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
{
ERR_sqlite3(db);
return ;
}
printf("插入历史记录成功\n");
return ;
}
// 退出---
// 删除信息
int delete_ser(int sensfd, MSG *msgser, sqlite3 *db)
{
char sql[128]="";
char *errmsg=NULL;
sprintf(sql,"delete from yginfo where name=\"%s\";",msgser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//删除成功--反馈给客户端
bzero(msg,sizeof(MSG));
sprintf(msgser->recvmsg,"%s删除成功",msgser->info.name);
if(send(sensfd,msgser,sizeof(MSG),0)>0)
{
printf("删除成功\n");
}
insert_history(db,msgser->info.name,msgser->recvmsg);
}
// 修改员工信息
int Change_ser(int sensfd, MSG *msg_ser, sqlite3 *db)
{
MSG chan_info;//此结构体用来接收要修改的信息
char sql[128]="";
char *errmsg=NULL;
char name[30]="";
strcpy(name,msg_ser->info.name);//插入到历史记录表中
//判断要修改员工在不在数据库中
select_by_name(sensfd,msg_ser,db);
//接收要修改的字段
if(recv(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
switch(chan_info.msgtype)
{
case '1':
//修改年龄
bzero(sql,sizeof(sql));
sprintf(sql,"update yginfo set age=%d where name=\"%s\";",chan_info.info.age,msg_ser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//修改成功--反馈给客户端
bzero(&chan_info,sizeof(MSG));
strcpy(chan_info.recvmsg,"年龄修改成功");
if(send(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
printf("年龄修改成功\n");
}
insert_history(db,name,chan_info.recvmsg);
break;
case '2':
//修改性别>>");
bzero(sql,sizeof(sql));
sprintf(sql,"update yginfo set sex=\"%s\" where name=\"%s\";",chan_info.info.sex,msg_ser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//修改成功--反馈给客户端
strcpy(chan_info.recvmsg,"性别修改成功");
if(send(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
printf("性别修改成功\n");
}
insert_history(db,name,chan_info.recvmsg);
break;
case '3':
//修改手机号>>");
bzero(sql,sizeof(sql));
sprintf(sql,"update yginfo set tel=\"%s\" where name=\"%s\";",chan_info.info.tel,msg_ser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//修改成功--反馈给客户端
strcpy(chan_info.recvmsg,"手机号修改成功");
if(send(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
printf("手机号修改成功\n");
}
insert_history(db,name,chan_info.recvmsg);
break;
case '4':
//修改密码
bzero(sql,sizeof(sql));
sprintf(sql,"update yginfo set passwd=\"%s\" where name=\"%s\";",chan_info.info.passwd,msg_ser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//修改成功--反馈给客户端
strcpy(chan_info.recvmsg,"密码修改成功");
if(send(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
printf("密码修改成功\n");
}
insert_history(db,name,chan_info.recvmsg);
break;
case '5':
//修改家庭住址>>");
bzero(sql,sizeof(sql));
sprintf(sql,"update yginfo set addr=\"%s\" where name=\"%s\";",chan_info.info.addr,msg_ser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//修改成功--反馈给客户端
strcpy(chan_info.recvmsg,"家庭住址修改成功");
if(send(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
printf("家庭住址修改成功\n");
}
insert_history(db,name,chan_info.recvmsg);
break;
case '6':
//修改职位>>");
bzero(sql,sizeof(sql));
sprintf(sql,"update yginfo set work=\"%s\" where name=\"%s\";",chan_info.info.work,msg_ser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//修改成功--反馈给客户端
strcpy(chan_info.recvmsg,"职位修改成功");
if(send(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
printf("职位修改成功\n");
}
insert_history(db,name,chan_info.recvmsg);
break;
case '7':
//修改入职日期(格式2022.10.10)>>");
bzero(sql,sizeof(sql));
sprintf(sql,"update yginfo set date=\"%s\" where name=\"%s\";",chan_info.info.date,msg_ser->info.name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
ERR_sqlite3(db);
return -1;
}
//修改成功--反馈给客户端
strcpy(chan_info.recvmsg,"入职日期修改成功");
if(send(sensfd,&chan_info,sizeof(chan_info),0)>0)
{
printf("入职日期修改成功\n");
}
insert_history(db,name,chan_info.recvmsg);
break;
}
}
return 0;
}
//发送接收
void send_recv(int sfd, MSG *msg)
{
int res;
bzero(msg, sizeof(MSG));
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
exit;
}
printf("send success\n");
bzero(msg, sizeof(MSG));
res = recv(sfd, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
printf("接收失败\n");
exit;
}
else if (0 == res)
{
fprintf(stderr, "服务器关闭\n");
exit;
}
printf("接收成功\n");
return ;
}
//查找所有
int select_all(int sensfd, MSG *msgser, sqlite3 *db)
{
char sql[] = "select * from yginfo"; // 存放数据库查询语句
char **pres = NULL; // 存放数据库查询到的首地址
int row,column,i,j,k=0;
bzero(msg->recvmsg,sizeof(msg->recvmsg));
if (sqlite3_get_table(db, sql, &pres, &row, &column, NULL) != 0)
{
// 用户名密码错误
sprintf(msg->recvmsg,"没有员工");
ERR_sqlite3(db);
return -1;
}else{
for(i=0;i<=row;i++)
{
printf("row=%d,column=%d\n",row,column);
for(j=0;j<column;j++)
{
sprintf(msg->recvmsg+strlen(msg->recvmsg),"%s\t",pres[k++]);
}
strcat(msg->recvmsg,"\n");
}
}
if (send(sensfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
insert_history(db,msgser->info.name,msg->recvmsg);
}
// 查询信息
int select_by_name(int sensfd, MSG *msgser, sqlite3 *db)
{
char sql[128] = ""; // 存放数据库查询语句
char **pres = NULL; // 存放数据库查询到的首地址
int row,column,i,j,k=0;
bzero(msg->recvmsg,sizeof(msg->recvmsg));
sprintf(sql, "select * from yginfo where name=\"%s\";", msg->info.name);
if (sqlite3_get_table(db, sql, &pres, &row, &column, NULL) != 0)
{
//函数执行失败
ERR_sqlite3(db);
return -1;
}else if(0==row){
//未找到----用户名密码错误
sprintf(msg->recvmsg,"没有这个员工");
msg->msgtype='N';//未找到
}else{
for(i=0;i<=row;i++)
{
printf("row=%d,column=%d\n",row,column);
for(j=0;j<column;j++)
{
sprintf(msg->recvmsg+strlen(msg->recvmsg),"%s\t",pres[k++]);
}
strcat(msg->recvmsg,"\n");
}
msg->msgtype='O';//成功找到
}
if (send(sensfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
insert_history(db,msgser->info.name,msg->recvmsg);
if(0==row)
{
return -1;
}else return 0;
}
// 登陆
int do_login(int sfd, MSG *msg, sqlite3 *db)
{
char sql[128] = ""; // 存放数据库查询语句
char **pres = NULL; // 存放数据库查询到的首地址
sprintf(sql, "select * from yginfo where name=\"%s\" and passwd=\"%s\";", msg->info.name, msg->info.passwd);
printf("%s\n", sql);
if (sqlite3_get_table(db, sql, &pres, NULL, NULL, NULL) != 0)
{
// 用户名密码错误
printf("用户名或密码错误\n");
ERR_sqlite3(db);
return -1;
}
else
{
// 可以登陆
bzero(msg, sizeof(MSG));
strcpy(msg->recvmsg, "login_ok");
}
// 给客户端传递可登陆信号
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
insert_history(db,msg->info.name,msg->recvmsg);
printf("可登陆,发送成功\n");
return 0;
}
// 更新select文件描述符
int updateMaxfd(int maxfd, fd_set readfds)
{
for (int j = maxfd; j >= 0; j--)
{
if (FD_ISSET(j, &readfds))
{
return j;
}
}
return 0;
}
sqlite3 *create_sqlitedb(void)
{
sqlite3 *db;
char *errmsg = NULL; // 指向错误信息的地址
if (sqlite3_open("./yuangong.db", &db) != SQLITE_OK)
{
ERR_sqlite3(db);
return NULL;
}
printf("数据库创建成功\n");
// 创建员工信息表
char sql[128] = "create table if not exists yginfo(name char,age int,sex char,work char,tel char,addr char,passwd char,date char,usertype char)";
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
ERR_sqlite3(db);
return NULL;
}
printf("员工表创建成功\n");
// 创建历史记录表
sprintf(sql, "create table if not exists history(time char,name char,opera char)");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
ERR_sqlite3(db);
return NULL;
}
printf("历史记录表创建成功\n");
return db;
}
// 添加员工信息
int ser_add(int sfd, MSG *msg, sqlite3 *db)
{
int ret_value = 0;
char *errmsg = NULL;
char sql[512] = "";
sprintf(sql, "insert into yginfo values(\"%s\", %d,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",%c);", msg->info.name,msg->info.age, msg->info.sex, msg->info.work, msg->info.tel, msg->info.addr, msg->info.passwd, msg->info.date,msg->info.usertype);
printf("%s", sql);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
{
printf("sqlite3_exec:%s %d\n", errmsg, __LINE__);
strcpy(msg->recvmsg, "插入失败");
ret_value = -1;
}
else
{
printf("添加成功\n");
strcpy(msg->recvmsg, "添加成功");
}
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
ret_value = -1;
}
insert_history(db,msg->info.name,msg->recvmsg);
return ret_value;
}
客户端
#include "yg.h"
int init_inet(void); //网络初始化
void send_recv(int sfd, MSG *msg);//接收发送
int do_login(int sfd);//登陆
int root_login(int sfd,MSG *msg);//管理员登陆
int root_menu(int sfd);//管理员登陆界面
int user_login(int sfd,MSG *msg);//普通用户登陆
// root用户功能函数
int Select_fun(int sfd);//查询
int Change_fun(int sfd);//修改
void change_by_name(int sfd);//查找名字修改
int Add_fun(int sfd);//添加
int Delete_fun(int sfd);//删除
int History(int sfd);//历史记录
//普通用户功能函数
int main(int argc, const char *argv[])
{
int sfd = init_inet(); //连接服务器
while (1)
{
//system("clear");
printf("****************\n");
printf("*****1.登录*****\n");
printf("*****2.退出*****\n");
printf("****************\n");
scanf("%c", &choose);
while (getchar() != 10);
switch (choose)
{
case '1':
msg->msgtype='L';
do_login(sfd);
break;
case '2':
close(sfd);
exit(0);
}
}
close(sfd);
return 0;
}
int do_login(int sfd)
{
while (1)
{
printf("******0.管理员root********\n");
printf("******1.普通员工user******\n");
printf("******2.退出 *********\n");
printf("按数字键选择>>");
scanf("%c", &choose);
while(getchar()!=10);
switch (choose)
{
case '0':
msg->info.usertype='L';
root_login(sfd,msg);
break;
case '1':
msg->info.usertype='U';
user_login(sfd,msg);
break;
case '2':
exit(-1);
}
}
return 0;
}
int root_menu(int sfd)
{
int flag = 0; //返回上级标志位
char a;
while (1)
{
if (flag == 1)
{
break;
}
system("clear");
printf("******1.查询*******\n");
printf("******2.修改*******\n");
printf("******3.添加*******\n");
printf("******4.删除*******\n");
printf("******5.历史记录****\n");
printf("******6.退出********\n");
printf("*****按数字键选择*****\n");
scanf("%c", &a);
while(getchar()!=10);
switch (a)
{
case '1':
Select_fun(sfd);
break;
case '2':
Change_fun(sfd);
break;
case '3':
Add_fun(sfd);
break;
case '4':
Delete_fun(sfd);
break;
case '5':
History(sfd);
break;
case '6':
flag = 1;
break;
}
}
return 0;
}
int Change_fun(int sfd)
{
msg->msgtype='C';
printf("请输入要修改的用户名>>");
scanf("%s", msg->info.name);
while(getchar()!=10);
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
printf("要修改的用户名%s", msg->info.name);
printf("send success---------\n");
bzero(msg, sizeof(MSG));
res = recv(sfd, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
return -1;
}
else if (0 == res)
{
fprintf(stderr, "服务器关闭\n");
return -1;
}
if(strcmp(msg->recvmsg, "没有这个员工")==0)
{ //用户不存在
printf("没有这个员工>>");
}else if(msg->msgtype='O')
{
change_by_name(sfd); //发送要修改的字段
}
return 0;
}
//根据名字修改某字段
void change_by_name(int sfd)
{
printf("******1.年龄****\n");
printf("******2.性别********\n");
printf("******3.手机号*****\n");
printf("******4.密码*****\n");
printf("******5.家庭住址*****\n");
printf("******6.职位*****\n");
printf("******7.入职年月*****\n");
printf("请输入要修改的字段>>");
scanf("%c", &choose);
while(getchar()!=10);
switch (choose)
{
case '1':
msg->msgtype='1';
printf("输入年龄>>");
scanf("%d", &msg->info.age);
while(getchar()!=10);
send_recv(sfd,msg);
break;
case '2':
msg->msgtype='2';
printf("输入性别>>");
scanf("%s", msg->info.sex);
while(getchar()!=10);
send_recv(sfd,msg);
break;
case '3':
msg->msgtype='3';
printf("输入手机号>>");
scanf("%s", msg->info.tel);
while(getchar()!=10);
send_recv(sfd,msg);
break;
case '4':
msg->msgtype='4';
printf("输入密码>>");
scanf("%s", msg->info.passwd);
while(getchar()!=10);
send_recv(sfd,msg);
break;
case '5':
msg->msgtype='5';
printf("输入家庭住址>>");
scanf("%s", msg->info.addr);
while(getchar()!=10);
send_recv(sfd,msg);
break;
case '6':
msg->msgtype='6';
printf("输入职位>>");
scanf("%s", msg->info.work);
while(getchar()!=10);
send_recv(sfd,msg);
break;
case '7':
msg->msgtype='7';
printf("输入入职日期(格式2022.10.10)>>");
scanf("%s", msg->info.date);
while(getchar()!=10);
send_recv(sfd,msg);
break;
}
printf("请输入返回上一级>>>");
while(getchar()!=10);
return ;
}
int Add_fun(int sfd)
{
bzero(msg,sizeof(MSG));
printf("请输入姓名>>");
scanf("%s",msg->info.name);
while(getchar()!=10);
printf("请输入年龄>>");
scanf("%d",&msg->info.age);
while(getchar()!=10);
printf("请输入性别>>");
scanf("%s",msg->info.sex);
while(getchar()!=10);
printf("请输入职位>>");
scanf("%s",msg->info.work);
while(getchar()!=10);
printf("请输入电话>>");
scanf("%s",msg->info.tel);
while(getchar()!=10);
printf("请输入家庭住址>>");
scanf("%s",msg->info.addr);
while(getchar()!=10);
printf("请输入密码>>");
scanf("%s",msg->info.passwd);
while(getchar()!=10);
printf("请输入入职日期>>");
scanf("%s",msg->info.date);
while(getchar()!=10);
printf("请输入用户类型root(0) user(1)>>");
scanf("%c",&msg->info.usertype);
while(getchar()!=10);
MSG *recv_ser;
msg->msgtype='A';
send_recv(sfd,msg);
printf("%s\n",recv_ser->recvmsg);
return 0;
}
int Delete_fun(int sfd)
{ msg->msgtype='D';
printf("请输入要删除的员工姓名>>");
scanf("%s",msg->info.name);
send_recv(sfd,msg);
printf("%s\n",msg->recvmsg);
return 0;
}
int History(int sfd)
{
msg->msgtype='H';
strcpy(msg->info.name,"admin");
send_recv(sfd,msg);
printf("shchu\n");
printf("%s\n",msg->recvmsg);
return 0;
}
int Select_fun(int sfd)
{
int quit = 0;
while (1)
{
if (quit == 1)
{
break;
}
printf("******1.按人名查找*******\n");
printf("******2.查找所有 *******\n");
printf("******0.返回上一级*******\n");
scanf("%c", &choose);
while(getchar()!=10);
switch (choose)
{
case '0':
quit = 1;
break;
case '1':
msg->msgtype='F'; //server端通过此知道是人名查找
printf("请输入要查找的人名>>");
scanf("%s", msg->info.name);
while(getchar()!=10);
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
bzero(msg, sizeof(MSG));
res = recv(sfd, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
return -1;
}
else if (0 == res)
{
fprintf(stderr, "服务器关闭\n");
break;
}
//打印查找内容
printf("%s", msg->recvmsg);
break;
case '2':
bzero(msg, sizeof(MSG));
msg->msgtype='s';//查找所有
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
bzero(msg, sizeof(MSG));
res = recv(sfd, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
return -1;
}
else if (0 == res)
{
fprintf(stderr, "服务器关闭\n");
break;
}
//打印查找内容
printf("%s", msg->recvmsg);
break;
}
}
}
//普通用户登陆
int user_login(int sfd,MSG *msg)
{
int res;
char a;
printf("输入用户名>>");
scanf("%s", msg->info.name);
while(getchar()!=10);
printf("请输入密码>>");
scanf("%s", msg->info.passwd);
while(getchar()!=10);
//发送给服务器
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
printf("send success\n");
//接收前清空,判断是否登陆成功
bzero(msg, sizeof(MSG));
res = recv(sfd, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
return -1;
}
else if (0 == res)
{
fprintf(stderr, "服务器关闭\n");
exit(-1);
}
else
{
if (strcmp(msg->recvmsg, "login_ok"))
{
//登陆失败
printf("用户名或密码错误\n");
exit(-1);
}
else
{
//登陆成功---跳转普通用户界面
printf("1.查询\n");
printf("2.修改\n");
printf("3.历史记录\n");
scanf("%s",&a);
while(getchar()!=10);
}
}
return 0;
}
//管理员登陆
int root_login(int sfd,MSG *msg)
{
int res;
printf("输入用户名>>");
scanf("%s", msg->info.name);
while(getchar()!=10);
printf("请输入密码>>");
scanf("%s", msg->info.passwd);
while(getchar()!=10);
//发送给服务器
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
return -1;
}
printf("send success\n");
//接收前清空,判断是否登陆成功
bzero(msg, sizeof(MSG));
res = recv(sfd, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
return -1;
}
else if (0 == res)
{
fprintf(stderr, "服务器关闭\n");
exit(-1);
}
else
{
if (strcmp(msg->recvmsg, "login_ok"))
{
//登陆失败
printf("用户名或密码错误\n");
exit(-1);
}
else
{
//登陆成功---跳转管理员菜单
root_menu(sfd);
}
}
return 0;
}
void send_recv(int sfd, MSG *msg)
{
int res;
if (send(sfd, msg, sizeof(MSG), 0) < 0)
{
ERR("send");
exit;
}
printf("send success\n");
bzero(msg, sizeof(MSG));
res = recv(sfd, msg, sizeof(MSG), 0);
if (res < 0)
{
ERR("recv");
printf("接收失败\n");
exit;
}
else if (0 == res)
{
fprintf(stderr, "服务器关闭\n");
exit;
}
printf("接收成功\n");
printf("%s\n",msg->recvmsg);
return ;
}
//网络初始化
int init_inet()
{
//创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0)
{
ERR("socket");
return -1;
}
int reuse = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR("setsockopt failed");
return -1;
}
//填充要连接的服务器的IP和端口
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
//连接服务器
if (connect(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
ERR("connect");
return -1;
}
return sfd;
}