本项目通过使用VMware Workstation Pro + sqlite3数据库实现一个简单的员工管理系统,包含的知识点有:tcp通信、setsockopt网络属性设置、网络超时检测、IO多路复用、字符串解析等知识点。
简单的员工管理系统:
需求分析:
(1)设计一个可以实现管理员注册登录的界面,通过注册登录进入管理系统,同时可以查看管理员的信息、修改密码等功能;
(2)通过命令解析的方式实现服务器对客户端命令控制,根据输入的命令进行业务处理,实现通信;
(3)需要通过C接口去实现C和sqlite3数据库的连接,将所有的信息保存在数据库的表中;
(4)实现多对一,即客户端多窗口对服务器的多窗口通信,不阻塞接收客户端的命令;
(5)客户端和服务器进行关联后,通过客户端发送指令,在客户端和服务器打印出插入在数据库中的信息。
功能菜单:
1.管理员注册登录:
2.管理员对员工信息的操作
3.管理员信息设置
代码实现:
客户端net.h头文件
#ifndef _NET_H
#define _NET_H
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sqlite3.h>
#define N 150
typedef struct user_massage
{
char username[20]; //用户名
char pwd[20]; //密码
}Us;
typedef struct staff
{
int id; //员工编号
char name[20]; //员工姓名
char sex[20]; //性别
int age; //年龄
char position[20]; //岗位
float salary; //薪水
}staff;
int jiexi(char *buf,char *cmd,char *filename);
int login_com(int tcp_socket);
int sigin_user(int tcp_socket,char *cmd,char *filename);
int login_user(int tcp_socket,char *cmd,char *filename);
int login_each(int tcp_socket,char *cmd,char *filename);
int delete_user(int tcp_socket,char *cmd,char *filename);
int update_user(int tcp_socket,char *cmd,char *filename);
int dowork_insert(int tcp_socket,char *cmd,char *filename);
int dowork_delete(int tcp_socket,char *cmd,char *filename);
int dowork_select(int tcp_socket,char *cmd,char *filename);
int dowork_update(int tcp_socket,char *cmd,char *filename);
int login_jiexi(char *str,char *username,char *pwd);
int tcp_com(int tcp_socket);
#endif
客户端client.c
#include "../include/net.h"
//函数功能:连接服务器
int tcp_connect(const char *ip,int port)
{
//创建套接字
int tcp_socket = socket(AF_INET,SOCK_STREAM,0);
if(tcp_socket < 0)
{
perror("socket error!");
return -1;
}
printf("socket ok!\n");
//设置对方ip和端口号port
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(ip);
server.sin_port = htons(port);
//请求连接
if(connect(tcp_socket,(struct sockaddr *)&server,sizeof(server)) < 0)
{
perror("connect error");
return -1;
}
printf("connect ok\n");
return tcp_socket;
}
//函数功能:用户登陆-->登陆管理系统
int login_com(int tcp_socket)
{
//发
int op = 0;
char buf[50] = {'\0'};
char cmd[50] = {'\0'};
char filename[50] = {'\0'};
while(1)
{
printf("*********************************\n");
printf("** **\n");
printf("** 坤坤员工管理系统 **\n");
printf("*1-------sigin user#---注册------\n");
printf("*2-------login user#---登陆------\n");
printf("*3----------quit#------退出------\n");
printf("** **\n");
printf("*********************************\n");
printf("--请输入指令进行操作--:\n");
scanf("%d",&op);
switch(op)
{
case 1:
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"sigin user#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
//命令解析
jiexi(buf,cmd,filename);
//注册用户
sigin_user(tcp_socket,cmd,filename);
break;
}
case 2:
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"login user#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
//命令解析
jiexi(buf,cmd,filename);
//登陆用户
login_user(tcp_socket,cmd,filename);
break;
}
case 3:
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"quit#");
send(tcp_socket,buf,sizeof(buf),0);
return 0;
}
default:
{
printf("您输入的指令有误,请重新输入!\n");
break;
}
}
}
}
//函数功能:注册用户
int sigin_user(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"sigin",5) == 0)
{
sleep(1);
char buf[N] = {'\0'};
memset(buf,'\0',sizeof(buf));
printf("请输入用户名和密码 (格式为username=xx&pwd=xx#):\n");
fgets(buf,sizeof(buf),stdin);
send(tcp_socket,buf,sizeof(buf),0);
char buf1[N] = {'\0'};
recv(tcp_socket,buf1,sizeof(buf1),0);
printf("%s\n",buf1);
}
return 0;
}
//函数功能:登陆账号
int login_user(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"login",5) == 0)
{
Us s1;
Us s2;
char buf2[N] = {'\0'};
memset(buf2,'\0',sizeof(buf2));
printf("请输入用户名和密码 (格式为username=xx&pwd=xx#)\n");
fgets(buf2,sizeof(buf2),stdin);
send(tcp_socket,buf2,sizeof(buf2),0);
recv(tcp_socket,&s1,sizeof(s1),0);
recv(tcp_socket,&s2,sizeof(s2),MSG_DONTWAIT);
if(strncmp(s1.username,"receive",7) == 0 && strncmp(s2.username,"nouser",6) == 0)
{
printf("登陆成功!\n");
//登陆成功后调用通信函数,进行下一步操作
tcp_com(tcp_socket);
}
else if(strncmp(s1.username,"nouser",6) == 0)
{
printf("登陆失败!没有该用户或密码错误!\n");
return -1;
}
}
return 0;
}
//函数功能:遍历->查看用户信息
int login_each(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"uselect",7) == 0)
{
sleep(1);
while(1)
{
char buf1[20] = {'\0'};
char buf2[20] = {'\0'};
memset(buf1,'\0',sizeof(buf1));
memset(buf2,'\0',sizeof(buf2));
recv(tcp_socket,buf1,sizeof(buf1),MSG_DONTWAIT);
recv(tcp_socket,buf2,sizeof(buf2),MSG_DONTWAIT);
if('\0' == buf1[0] && '\0' == buf2[0])
{
printf("打印完毕!\n");
break;
}
printf("username = %s pwd = %s\n",buf1,buf2);
}
}
return 0;
}
//函数功能:删除用户信息
int delete_user(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"udelete",7) == 0)
{
sleep(1);
char buf1[20] = {'\0'};
char buf2[20] = {'\0'};
memset(buf1,'\0',sizeof(buf1));
printf("请输入要删除的用户名:\n");
scanf("%s",buf1);
send(tcp_socket,buf1,sizeof(buf1),0);
//memset(buf2,'\0',sizeof(buf2));
recv(tcp_socket,buf2,sizeof(buf2),0);
printf("%s\n",buf2);
}
return 0;
}
//函数功能:修改用户信息->修改用户密码
int update_user(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"uupdate",7) == 0)
{
sleep(1);
printf("请输入用户名和修改的密码(eg:abc 123#):\n");
char buf1[20] = {'\0'};
char buf2[20] = {'\0'};
char buf3[20] = {'\0'};
memset(buf1,'\0',sizeof(buf1));
fgets(buf1,sizeof(buf1),stdin);
send(tcp_socket,buf1,sizeof(buf1),0);
recv(tcp_socket,buf2,sizeof(buf2),0);
recv(tcp_socket,buf3,sizeof(buf3),0);
printf("修改后的用户的信息为:username=%s pwd=%s\n",buf2,buf3);
return 0;
}
return 0;
}
//函数功能:执行插入
int dowork_insert(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"insert",6) == 0)
{
sleep(1);
staff s1;
char buf[N] = {'\0'};
memset(&s1,0,sizeof(s1));
printf("请输入您要插入的员工信息:(id name sex age position salary)\n");
scanf("%d%s%s%d%s%f",&s1.id,s1.name,s1.sex,&s1.age,s1.position,&s1.salary);
send(tcp_socket,&s1,sizeof(s1),0);
// memset(buf,'\0',sizeof(buf));
recv(tcp_socket,buf,sizeof(buf),0);
printf("%s\n",buf);
}
return 0;
}
//函数功能:执行删除
int dowork_delete(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"delete",6) == 0)
{
sleep(1);
char buf1[20] = {'\0'};
char buf2[50] = {'\0'};
memset(buf1,'\0',sizeof(buf1));
printf("请输入要删除的员工的id号:\n");
fgets(buf1,sizeof(buf1),stdin);
send(tcp_socket,buf1,sizeof(buf1),0);
recv(tcp_socket,buf2,sizeof(buf2),0);
printf("%s\n",buf2);
}
return 0;
}
//函数功能:执行查看
int dowork_select(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"select",6) == 0)
{
sleep(1);
while(1)
{
staff s1;
memset(&s1,'\0',sizeof(s1));
recv(tcp_socket,&s1,sizeof(s1),MSG_DONTWAIT);
if(s1.id == 0)
{
printf("打印完成!\n");
break;
}
printf("id=%d name=%s sex=%s age=%d position=%s salary=%.1f\n",s1.id,s1.name,s1.sex,s1.age,s1.position,s1.salary);
}
}
return 0;
}
//函数功能:执行更新
int dowork_update(int tcp_socket,char *cmd,char *filename)
{
if(strncmp(cmd,"update",6) == 0)
{
char buf[N] = {'\0'};
sleep(1);
staff s1;
printf("请输入要修改的员工信息的编号\n");
scanf("%d",&s1.id);
printf("请输入修改后的员工信息!\n");
scanf("%s %s %d %s %f",s1.name,s1.sex,&s1.age,s1.position,&s1.salary);
send(tcp_socket,&s1,sizeof(s1),0);
memset(buf,'\0',sizeof(buf));
recv(tcp_socket,buf,sizeof(buf),0);
printf("%s\n",buf);
return 0;
}
}
//函数功能:命令解析
int jiexi(char *buf,char *cmd,char *filename)
{
while(*buf != '#')
{
if(*buf == ' ')
{
*cmd = '\0';
buf++;
break;
}
*cmd = *buf;
buf++;
cmd++;
}
while(*buf != '#')
{
*filename = *buf;
buf++;
filename++;
}
*filename = '\0';
return 0;
}
//函数功能:登陆解析
int login_jiexi(char *str,char *username,char *pwd)
{ while(*str != '#')
{
if(*str == '=')
{
break;
}
str++;
}
str++;
while(*str != '#')
{
if(*str == '&')
{
break;
}
*username = *str;
str++;
username++;
}
str++;
*username = '\0';
while(*str != '#')
{
if(*str == '=')
{
break;
}
str++;
}
str++;
while(*str != '#')
{
*pwd = *str;
str++;
pwd++;
}
*pwd = '\0';
return 0;
}
//函数功能:通信
int tcp_com(int tcp_socket)
{
int value = 0;
char buf[50] = {'\0'};
char cmd[50] = {'\0'};
char filename[50] = {'\0'};
while(1)
{
printf("************************************\n");
printf(" \n");
printf("** 😲 坤坤员工管理系统 😲 **\n");
printf("*1--------insert staff#---------插入\n");
printf("*2--------delete staff#---------删除\n");
printf("*3--------select staff#---------查看\n");
printf("*4--------update staff#---------更新\n");
printf("*5--------to set users----------设置\n");
printf("*6------------quit#-------------退出\n");
printf(" \n");
printf("************************************\n");
printf("--请输入选项进行操作--:\n");
scanf("%d",&value);
switch(value)
{
case 1: //插入
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"insert staff#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
jiexi(buf,cmd,filename);
//执行插入
dowork_insert(tcp_socket,cmd,filename);
break;
}
case 2: //删除
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"delete staff#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
jiexi(buf,cmd,filename);
//执行删除
dowork_delete(tcp_socket,cmd,filename);
break;
}
case 3: //查看
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"select staff#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
jiexi(buf,cmd,filename);
//执行查看
dowork_select(tcp_socket,cmd,filename);
break;
}
case 4: //修改
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"update staff#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
jiexi(buf,cmd,filename);
//执行修改
dowork_update(tcp_socket,cmd,filename);
break;
}
case 5: //用户设置
{
system("clear");
int op1 = 0;
char buf[50] = {'\0'};
char cmd[50] = {'\0'};
char filename[50] = {'\0'};
while(1)
{
printf("******************************************\n");
printf(" \n");
printf("** 😂 坤坤员工管理系统 😂 **\n");
printf("** 用户信息相关设置 **\n");
printf("*1----------select user#-------查看用户---\n");
printf("*2----------delete user#-------删除用户---\n");
printf("*3----------update user#-------修改密码---\n");
printf("*4--------------quit#----------退出程序---\n");
printf(" \n");
printf("******************************************\n");
printf("--请输入选项进行操作--:\n");
scanf("%d",&op1);
switch(op1)
{
case 1: //查看用户信息
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"uselect user#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
jiexi(buf,cmd,filename);
//遍历
login_each(tcp_socket,cmd,filename);
break;
}
case 2: //删除用户信息
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"udelete user#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
jiexi(buf,cmd,filename);
//删除用户信息
delete_user(tcp_socket,cmd,filename);
break;
}
case 3: //修改用户密码
{
system("clear");
memset(buf,'\0',sizeof(buf));
strcpy(buf,"uupdate user#");
getchar();
send(tcp_socket,buf,sizeof(buf),0);
jiexi(buf,cmd,filename);
//修改用户密码
update_user(tcp_socket,cmd,filename);
break;
}
case 4: //退出程序
{
return 0;
}
default:
{
printf("您输入的指令有误,请重新输入!\n");
break;
}
}
}
}
case 6:
{
return 0;
}
default:
{
printf("您输入的指令有误,请重新输入!\n");
break;
}
}
}
}
int main(int argc, const char *argv[])
{
//连接tcp服务器
int tcp_socket = tcp_connect(argv[1],atoi(argv[2]));
//通信
login_com(tcp_socket);
//关闭套接字
close(tcp_socket);
return 0;
}
服务器net.h头文件
#ifndef _NET_H
#define _NET_H
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sqlite3.h>
#define N 150
typedef struct user_massage
{
char username[20]; //用户名
char pwd[20]; //密码
}us;
typedef struct staff
{
int id; //员工编号
char name[20]; //员工姓名
char sex[20]; //性别
int age; //年龄
char position[20]; //岗位
float salary; //薪水
}staff;
//子函数声明
int tcp_com(int newfd);
int jiexi_order(char *buf,char *cmd,char *filename);
int jiexi_login(char *buf,char *username,char *pwd);
sqlite3 *sql_open(char *filename);
int create_table(sqlite3 *db,char *filename);
int create_usertable(sqlite3 *db);
int sigin_user(sqlite3 *db,char *filename,int newfd);
int callback1(void *data,int columnNum,char *columnValue[],char *columnName[]);
int login_user(sqlite3 *db,char *filename,int newfd);
int callback2(void *data,int columnNum,char *columnValue[],char *columnName[]);
int select_user(sqlite3 *db,char *filename,int newfd);
int delete_user(sqlite3 *db,char *filename,int newfd);
int update_user(sqlite3 *db,char *filename,int newfd);
int callback(void *data,int columnNum,char *columnValue[],char *columnName[]);
int insert_data(sqlite3 *db,char *filename,int newfd);
int delete_data(sqlite3 *db,char *filename,int newfd);
int update_data(sqlite3 *db,char *filename,int newfd);
int select_data(sqlite3 *db,char *filename,int newfd);
int dowork(int newfd,char *cmd,char *filename);
#endif
服务器server.c
#include "../include/net.h"
//函数功能:监听是否有客户端的连接
int tcp_listen(const char *ip,int port)
{
//创建套接字
int tcp_socket = socket(AF_INET,SOCK_STREAM,0);
if(tcp_socket < 0)
{
perror("socket error");
return -1;
}
printf("socket ok\n");
//设置允许ip地址和端口号可以被重复使用
int resaddr;
setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR,&resaddr,sizeof(resaddr));
//设置自己的ip和端口号
struct sockaddr_in myaddr;
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = inet_addr(ip);
myaddr.sin_port = htons(port);
//绑定
if(bind(tcp_socket,(struct sockaddr *)&myaddr,sizeof(myaddr)) < 0)
{
perror("bind error");
return -1;
}
printf("bind ok\n");
//监听是否有客户端的连接
if(listen(tcp_socket,5) < 0)
{
perror("listen error");
return -1;
}
printf("listen ok\n");
return tcp_socket;
}
//函数功能:命令解析
int jiexi_order(char *buf,char *cmd,char *filename)
{
while(*buf != '#')
{
if(*buf == ' ')
{
*cmd = '\0';
buf++;
break;
}
*cmd = *buf;
buf++;
cmd++;
}
while(*buf != '#')
{
*filename = *buf;
buf++;
filename++;
}
*filename = '\0';
return 0;
}
//函数功能:登陆解析
int jiexi_login(char *str,char *username,char *pwd)
{
while(*str != '#')
{
if(*str == '=')
{
break;
}
str++;
}
str++;
while(*str != '#')
{
if(*str == '&')
{
break;
}
*username = *str;
str++;
username++;
}
str++;
*username = '\0';
while(*str != '#')
{
if(*str == '=')
{
break;
}
str++;
}
str++;
while(*str != '#')
{
*pwd = *str;
str++;
pwd++;
}
*pwd = '\0';
return 0;
}
//函数功能:tcp通信
int tcp_com(int newfd)
{
//收
char buf[50] = {'\0'};
char cmd[50] = {'\0'};
char filename[50] = {'\0'};
memset(buf,'\0',sizeof(buf));
recv(newfd,buf,sizeof(buf),0);
if(strncasecmp(buf,"quit",4) == 0)
{
return -1;
}
//命令解析
jiexi_order(buf,cmd,filename);
printf("filename=%s\n",filename);
//业务处理
dowork(newfd,cmd,filename);
return 0;
}
//函数功能:打开数据库
sqlite3 *sql_open(char *filename)
{
sqlite3 *db = NULL;
//参数1:数据库名
//参数2:数据库的连接对象
int ret = sqlite3_open(filename,&db);
if(ret != SQLITE_OK)
{
perror("打开数据库失败!\n");
return NULL;
}
printf("打开数据库成功!\n");
return db;
}
//函数功能:创建管理员表
int create_usertable(sqlite3 *db)
{
char sql[N] = "create table if not exists user (username text primary key not null,pwd text)";
printf("%s\n",sql);
char *errmsg = NULL;
int rm = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(rm != SQLITE_OK)
{
printf("创建用户表失败! %s\n",errmsg);
return -1;
}
printf("创建用户表成功!\n");
return 0;
}
//函数功能:创建员工表
int create_table(sqlite3 *db,char *filename)
{
// char sql[N] = {'\0'};
// sprintf(sql,"create table if not exists %s (id int primary key not null,name text,shelflife real)",filename);
char sql[N] = "create table if not exists staff (id int primary key not null,name text,sex text,age int,position text,salary float)";
printf("%s\n",sql);
char *errmsg = NULL;
int ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != 0)
{
printf("创建员工表失败! %s\n",errmsg);
return -1;
}
printf("创建员工表成功!\n");
return 0;
}
//函数功能:注册用户
int sigin_user(sqlite3 *db,char *filename,int newfd)
{
char buf[N] = {'\0'};
char username[N] = {'\0'};
char pwd[N] = {'\0'};
recv(newfd,buf,sizeof(buf),0);
jiexi_login(buf,username,pwd);
printf("%s %s",username,pwd);
char *errmsg = NULL;
char sql[N] = {'\0'};
sprintf(sql,"insert into %s values('%s','%s')",filename,username,pwd);
printf("%s\n",sql);
int ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
fprintf(stderr,"插入错误/失败:%s\n",errmsg);
return -1;
}
printf("用户注册成功!\n");
char buf1[N] = {'\0'};
strcpy(buf1,"用户注册成功");
send(newfd,buf1,sizeof(buf1),0);
return 0;
}
//函数功能:管理员登陆的回调函数
//参数1:给回调函数传递的参数
//参数2:记录中包含的字段数目(几列就是几)
//参数3:记录中包含的字段的值
//参数4:记录中包含的字段的名
int callback1(void *data,int columnNum,char *columnValue[],char *columnName[])
{
int *qt = (int *)data;
int newfd = *qt;
us s1;
memset(&s1,'\0',sizeof(us));
strcpy(s1.username,"receive");
strcpy(s1.pwd,columnValue[1]);
printf("%s %s\n",s1.username,s1.pwd);
send(newfd,&s1,sizeof(s1),0);
printf("login ok\n");
return 0;
}
//函数功能:用户登陆
int login_user(sqlite3 *db,char *filename,int newfd)
{
us s1;
char buf[N] = {'\0'};
char username[20] = {'\0'};
char pwd[20] = {'\0'};
recv(newfd,&buf,sizeof(buf),0);
//登陆解析
jiexi_login(buf,username,pwd);
char sql[N] = {'\0'};
sprintf(sql,"select * from user where username = '%s' and pwd = '%s'",username,pwd);
printf("%s\n",sql);
//参数1:连接对象 sqlite3 *db
//参数2:sql语句
//参数3:回调函数
//参数4:给回调函数传参
//参数5:保存错误信息
char *errmsg = NULL;
int ret = sqlite3_exec(db,sql,callback1,&newfd,&errmsg);
if(ret != SQLITE_OK)
{
fprintf(stderr,"select error:%s\n",errmsg);
return -1;
}
strcpy(s1.username,"nouser");
send(newfd,&s1,sizeof(s1),0);
return 0;
}
//函数功能:查看管理员信息的回调函数
int callback2(void *data,int columnNum,char *columnValue[],char *columnName[])
{
int *qt = (int *)data;
int newfd = *qt;
char buf1[20] = {'\0'};
char buf2[20] = {'\0'};
memset(buf1,'\0',sizeof(buf1));
memset(buf2,'\0',sizeof(buf2));
strcpy(buf1,columnValue[0]);
strcpy(buf2,columnValue[1]);
printf("username = %s pwd = %s\n",buf1,buf2);
send(newfd,buf1,sizeof(buf1),0);
send(newfd,buf2,sizeof(buf2),0);
return 0;
}
//函数功能:查看管理员信息
int select_user(sqlite3 *db,char *filename,int newfd)
{
char sql[N] = {'\0'};
printf("%s\n",filename);
sprintf(sql,"select * from %s",filename);
char *errmsg = NULL;
int ret = sqlite3_exec(db,sql,callback2,&newfd,&errmsg);
if(ret != SQLITE_OK)
{
fprintf(stderr,"查看用户信息失败:%s\n",errmsg);
return -1;
}
printf("select ok!\n");
return 0;
}
//函数功能:删除管理员信息
int delete_user(sqlite3 *db,char *filename,int newfd)
{
char id[20] = {'\0'};
recv(newfd,id,sizeof(id),0);
char sql[N] = {'\0'};
char *errmsg = NULL;
sprintf(sql,"delete from user where username = '%s'",id);
printf("%s\n",sql);
int ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
perror("delete error!\n");
return -1;
}
printf("delete ok!\n");
char buf2[N] = {'\0'};
strcpy(buf2,"delete ok");
send(newfd,buf2,sizeof(buf2),0);
return 0;
}
//函数功能:更新用户信息/修改密码
int update_user(sqlite3 *db,char *filename,int newfd)
{
char buf[N] = {'\0'};
char username[20] = {'\0'};
char pwd[20] = {'\0'};
recv(newfd,buf,sizeof(buf),0);
jiexi_order(buf,username,pwd);
char *errmsg = NULL;
char sql[N] = {'\0'};
sprintf(sql,"update %s set pwd = '%s' where username = '%s'",filename,pwd,username);
printf("%s\n",sql);
int ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
perror("密码修改失败!\n");
return -1;
}
memset(sql,'\0',sizeof(sql));
sprintf(sql,"select * from user where username = '%s'",username);
printf("%s\n",sql);
int rem = sqlite3_exec(db,sql,callback2,&newfd,&errmsg);
if(rem != SQLITE_OK)
{
perror("密码修改失败!\n");
return -1;
}
printf("密码修改成功!\n");
// char str[]
}
//函数功能:插入数据->执行插入
int insert_data(sqlite3 *db,char *filename,int newfd)
{
staff s1;
// memset(&s1,0,sizeof(s1));
recv(newfd,&s1,sizeof(s1),0);
printf("%d %s %s %d %s %.1f\n",s1.id,s1.name,s1.sex,s1.age,s1.position,s1.salary);
char *errmsg = NULL;
char sql[N] = {'\0'};
sprintf(sql,"insert into %s values (%d,'%s','%s',%d,'%s',%f)",filename,s1.id,s1.name,s1.sex,s1.age,s1.position,s1.salary);
printf("%s\n",sql);
int ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
fprintf(stderr,"插入数据失败:%s\n",errmsg);
return -1;
}
printf("插入数据成功!\n");
char buf[N] = {'\0'};
strcpy(buf,"insert data ok!\n");
send(newfd,buf,sizeof(buf),0);
return 0;
}
//函数功能:删除数据->执行删除
int delete_data(sqlite3 *db,char *filename,int newfd)
{
char id[20] = {'\0'};
recv(newfd,id,sizeof(id),0);
char sql[50] = {'\0'};
sprintf(sql,"delete from %s where id = %d",filename,atoi(id));
printf("%s\n",sql);
char *errmsg = NULL;
int ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
fprintf(stderr,"删除数据失败:%s\n",errmsg);
return -1;
}
printf("删除数据成功!\n");
char arr[20] = {'\0'};
strcpy(arr,"delete data ok!\n");
send(newfd,arr,sizeof(arr),0);
return 0;
}
//函数功能:查看员工信息的回调函数
int callback(void *data,int columnNum,char *columnValue[],char *columnName[])
{
int *qt = (int *)data;
int newfd = *qt;
staff s1;
memset(&s1,'\0',sizeof(staff));
s1.id = atoi(columnValue[0]);
strcpy(s1.name,columnValue[1]);
strcpy(s1.sex,columnValue[2]);
s1.age = atoi(columnValue[3]);
strcpy(s1.position,columnValue[4]);
s1.salary = atof(columnValue[5]);
printf("id=%d name=%s sex=%s age=%d position=%s salary=%.1f\n",s1.id,s1.name,s1.sex,s1.age,s1.position,s1.salary);
send(newfd,&s1,sizeof(s1),0);
// printf("id=%d name=%s sex=%s age=%d position=%s salary=%.1f\n",s1.id,s1.name,s1.sex,s1.age,s1.position,s1.salary);
// memset(&s1,'\0',sizeof(s1));
return 0;
}
//函数功能:查看/查看数据->执行查看
int select_data(sqlite3 *db,char *filename,int newfd)
{
char sql[N] = {'\0'};
sprintf(sql,"select * from %s",filename);
printf("%s\n",sql);
char *errmsg = NULL;
int ret = sqlite3_exec(db,sql,callback,&newfd,&errmsg);
if(ret != SQLITE_OK)
{
fprintf(stderr,"查找/查看数据失败:%s\n",errmsg);
return -1;
}
/* staff s1;
memset(&s1,'\0',sizeof(staff));
strcpy(s1.name,"发完了");
send(newfd,&s1,sizeof(s1),0);
*/ printf("查找/查看数据成功!\n");
return 0;
}
//函数功能:执行更新
int update_data(sqlite3 *db,char *filename,int newfd)
{
staff s1;
memset(&s1,0,sizeof(s1));
recv(newfd,&s1,sizeof(s1),0);
printf("%d %s %s %d %s %f\n",s1.id,s1.name,s1.sex,s1.age,s1.position,s1.salary);
char *errmsg = NULL;
char sql[N] = {'\0'};
sprintf(sql,"update staff set name = '%s',sex = '%s',age = %d,position = '%s',salary = %f where id = %d",s1.name,s1.sex,s1.age,s1.position,s1.salary,s1.id);
printf("%s\n",sql);
int ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
fprintf(stderr,"修改数据失败:%s\n",errmsg);
return -1;
}
printf("修改数据成功!\n");
char buf[N] = {'\0'};
strcpy(buf,"update data ok!\n");
send(newfd,buf,sizeof(buf),0);
return 0;
}
//函数功能:业务处理函数
int dowork(int newfd,char *cmd,char *filename)
{
//打开数据库
sqlite3 *db = NULL;
db = sql_open("test.db");
if(strncmp(cmd,"select",6) == 0) //查找数据
{
//参数1:数据库的连接对象
//参数2:表名
//参数3:新生成的tcp连接对象
select_data(db,filename,newfd);
if(strncmp(cmd,"create",6) == 0)
{
create_table(db,filename); //创建表
}
}else if(strncmp(cmd,"delete",6) == 0) //删除数据
{
delete_data(db,filename,newfd);
}else if(strncmp(cmd,"update",6) == 0) //修改数据
{
update_data(db,filename,newfd);
}
else if(strncmp(cmd,"insert",6) == 0) //插入数据
{
insert_data(db,filename,newfd);
}else if(strncmp(cmd,"sigin",5) == 0) //用户注册
{
create_usertable(db);
sigin_user(db,filename,newfd);
}else if(strncmp(cmd,"login",5) == 0) //用户登陆
{
login_user(db,filename,newfd);
}else if(strncmp(cmd,"uselect",7) == 0) //查看/查找用户信息
{
select_user(db,filename,newfd);
}else if(strncmp(cmd,"udelete",7) == 0) //删除用户信息
{
delete_user(db,filename,newfd);
}
else if(strncmp(cmd,"uupdate",7) == 0) //更新用户信息(更改密码)
{
update_user(db,filename,newfd);
}
}
int main(int argc, const char *argv[])
{
if(argc < 3)
{
printf("请输入id和端口号执行操作!\n");
return -1;
}
//获得监听好的socket对象
int tcp_socket = tcp_listen(argv[1],atoi(argv[2]));
//接受连接生成新的socket对象
int newfd = 0;
//关心以下服务器端的ip地址和端口号
struct sockaddr_in client;
//1.定义两个文描述符的集合
fd_set rdfs;
fd_set temp;
//2.清空两个文件描述符的集合
FD_ZERO(&rdfs);
FD_ZERO(&temp);
//3.将监听的socket对象加入到文件描述符集合中
FD_SET(tcp_socket,&rdfs);
while(1)
{
temp = rdfs; //监听的是temp
struct timeval tv;
tv.tv_sec=5;
tv.tv_usec=0;
int reval=select(FD_SETSIZE,&temp,NULL,NULL,&tv);
if(reval<0)
{
perror("select error");
return -1;
}
else if(reval==0)
{
printf("select timeout\n");
}
else if(reval>0)
{
int i=0;
for(i=0;i<FD_SETSIZE;i++)
{
//判断哪个文件描述符否有数据
if(FD_ISSET(i,&temp))
{
if(i==tcp_socket)
{
//若是监听socket,表示有客户端来连接
memset(&client,'\0',sizeof(client));
int len=sizeof(client);
newfd=accept(tcp_socket,(struct sockaddr *)&client,&len);
if(newfd<0)
{
perror("accept error");
return -1;
}
printf("client ip=%s port=%d acccept ok\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
FD_SET(newfd,&rdfs);//将新生成的socket加入集合中
}else
{
//通信套接字,表示客户端有数据可读
//3.TCP通信
int n=tcp_com(i);
if(n<0)
{
printf("%d断开了\n",i);
FD_CLR(i,&rdfs);//将文件描述符从集合中删除
//4.关闭socket对象
close(i);
}
}
}
}
}
}
close(tcp_socket);
return 0;
}
我们在书写完成之后,可以把工程目录写成makefile工程管理模式方便操作,另,在服务器端生成.o文件时需要引入sqlite3数据库,即编译内容为:gcc server.c -o s -lsqlite3
注意:如果我们在编译时提示这个错误:
描述:找不到头文件
原因:系统没有安装函数库
解决办法:输入下面的指令
sudo apt-get install libsqlite3-dev
留给读者一个问题:
代码段中设计了一个比较复杂的操作:在登录注册时需要输入完整的字符串去进行字符串比对,应该如何降低这个工作量呢?结合实际情况中的操作,我们只需要输入我们需要的账号段和密码段,而不需要去输入(账号:abc&密码123#)这种情况,读者不妨自己理解一下。
--------------------------------------------------------我是分割线------------------------------------------------------------end
写在文末:该网络编程项目是一个比较简单易懂的基础版项目,只是实现了简单的增删改查,在用户交互方面做的比较差,容易出现段错误以及数组越界等问题,读者可以结合实际情况去考虑这些问题。个人见解不深,读者若有问题,欢迎私信交流
/*原创内容,有任何问题欢迎私信*/