一、项目说明:
开发环境:Linux
开发语言:C语言
二、项目描述:本项目是基于TCP的,多进程实现并发服务器支持多客户端的访问。实现用户注册登录,查询信息,修改信息,管理员注册登录,增加,删除,修改,查询员工信息等。以下是代码,分为客户端和服务器端,只供参考。
服务器端:
#include <head.h>//自己定义的头文件,可以自己添加
#include <sqlite3.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#define R 1 //用户注册
#define L 2 //用户登录
#define D 3 //删除
#define M 4 //修改
#define Q 5 //查询
#define N 512
typedef struct MSG
{
int type; // 1为管理员,2为普通用户
int type2; //用户选项
char name[16]; //管理员名字
char pd[128]; //密码或数据
int age;
int salary;
char data[N];
char data2[N];
char office[64];
int flag;
} msg_t;
int flag = 0; //控制打印表头的标志位 0 要打印 1 不打印
void do_client1(int, sqlite3 *, msg_t *);
int do_register(int acceptfd, msg_t *, sqlite3 *);
int do_login(int, msg_t *, sqlite3 *);
void do_delete(int, msg_t *, sqlite3 *);
void do_modify(int, msg_t *, sqlite3 *);
void do_query(int, msg_t *, sqlite3 *);
int callback(void *, int, char **, char **);
void handler()
{
wait(NULL);
}
int main(int argc, const char *argv[])
{
int sockfd;
if (argc != 3)
{
printf("Usage: %s <ip> <port>\n", argv[0]);
exit(-1);
}
//创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
PRINT_ERR("socket error");
}
//打开数据库
sqlite3 *db = NULL;
char *errmsg;
int ret = sqlite3_open("my.db", &db);
if (ret != SQLITE_OK)
{
PRINT_ERR("open error");
}
char buff[N] = {0};
sprintf(buff, "%s", "CREATE TABLE IF NOT EXISTS admin(aname TEXT PRIMARY KEY,pd TEXT)");
if (SQLITE_OK != (ret = sqlite3_exec(db, buff, NULL, NULL, &errmsg)))
{
printf("%s(%d): errcode:[%d] errmsg:[%s]\n", __FILE__, __LINE__, ret, errmsg);
exit(-1);
}
char buff1[N] = {0};
sprintf(buff1, "%s", "CREATE TABLE IF NOT EXISTS employee(uname TEXT PRIMARY KEY,pd TEXT,age INT,salary INT,office TEXT)");
if (SQLITE_OK != (ret = sqlite3_exec(db, buff1, NULL, NULL, &errmsg)))
{
printf("%s(%d): errcode:[%d] errmsg:[%s]\n", __FILE__, __LINE__, ret, errmsg);
exit(-1);
}
//创建服务器网络信息结构体
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons(atoi(argv[2]));
socklen_t addrlen = sizeof(server_addr);
//绑定套接字和网络信息结构体
if (-1 == bind(sockfd, (struct sockaddr *)&server_addr, addrlen))
{
PRINT_ERR("bind error");
}
//设置为被动监听状态
if (-1 == listen(sockfd, 100))
{
PRINT_ERR("listen error");
}
//读写数据
//处理僵尸进程
signal(SIGCHLD, handler);
pid_t pid;
msg_t msg;
//使用多进程实现并发服务器
while (1)
{
//阻塞等待客户端连接
int acceptfd = accept(sockfd, NULL, NULL);
if (-1 == acceptfd)
{
PRINT_ERR("accept error");
}
pid = fork();
if (pid < 0)
{
PRINT_ERR("fork error");
}
else if (pid == 0)
{
//子进程
recv(acceptfd, &msg, sizeof(msg_t), 0);
do_client1(acceptfd, db, &msg);
}
else
{
//父进程
close(acceptfd);
}
}
sqlite3_free(errmsg);
return 0;
}
void do_client1(int acceptfd, sqlite3 *db, msg_t *msg) //管理员
{
int n = 0;
AGAIN:
while (recv(acceptfd, msg, sizeof(msg_t), 0) > 0)
{
if (msg->type == 1)
{ //管理员
switch (msg->type2)
{
case R: //注册
if (0 != do_register(acceptfd, msg, db))
{ //注册失败
printf("注册管理员:%s失败\n", msg->name);
}
goto AGAIN;
break;
case L: //登录
if (do_login(acceptfd, msg, db) == 0) //登录成功
{
printf("进入管理员界面了\n");
goto AGAIN;
}
else
{
printf("管理员登录失败\n");
n++;
if (n == 2)
{
printf("%s退出了\n", msg->name);
exit(0);
}
goto AGAIN;
}
break;
case D: //删除
do_delete(acceptfd, msg, db);
break;
case M: //修改
do_modify(acceptfd, msg, db);
break;
case Q: //查询
do_query(acceptfd, msg, db);
break;
}
}
else if (msg->type == 2)
{ //普通用户
switch (msg->type2)
{
case R: //注册
if (0 != do_register(acceptfd, msg, db))
{ //注册失败
printf("注册用户:%s失败\n", msg->name);
}
goto AGAIN;
break;
case L: //登录
if (0 == do_login(acceptfd, msg, db))
{
printf("进入用户界面了\n");
goto AGAIN;
}
else
{
printf("用户登录失败\n");
n++;
if (n == 2)
{
printf("%s退出了\n", msg->name);
exit(0);
}
goto AGAIN;
}
break;
case M: //修改,只能修改除薪资和职务以外的数据
do_modify(acceptfd, msg, db);
break;
case Q: //普通用户只能查询自己的信息
do_query(acceptfd, msg, db);
break;
}
}
memset(msg, 0, sizeof(msg_t));
}
printf("%s退出了\n", msg->name);
exit(0);
}
//注册
int do_register(int acceptfd, msg_t *msg, sqlite3 *db)
{
char buff[512] = {0};
char *errmsg = NULL;
//使用sqlite3_exec函数判断是否能插入成功
//由于用户名设置为主键,所以如果用户名已经存在就会报错
if (msg->type == 1) //管理员
{
sprintf(buff, "INSERT INTO admin values('%s','%s')", msg->name, msg->pd);
if (sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
{
sprintf(msg->data, "管理员 %s 已存在!!!", msg->name);
send(acceptfd, msg, sizeof(msg_t), 0);
return -1;
}
else
{
strcpy(msg->data, "注册管理员成功");
printf("注册管理员:%s成功\n", msg->name);
send(acceptfd, msg, sizeof(msg_t), 0);
return 0;
}
}
else if (msg->type == 2) //普通用户
{
sprintf(buff, "INSERT INTO employee values('%s','%s','%d','%d','%s')", msg->name, msg->passwd, msg->age, msg->salary, msg->office);
if (sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
{
sprintf(msg->data, "用户 %s 已存在!!!", msg->name);
printf("注册用户:%s失败\n", msg->name);
send(acceptfd, msg, sizeof(msg_t), 0);
return -1;
}
else
{
strcpy(msg->data, "注册用户成功");
printf("注册用户:%s成功\n", msg->name);
send(acceptfd, msg, sizeof(msg_t), 0);
return 0;
}
}
}
//登录
int do_login(int acceptfd, msg_t *msg, sqlite3 *db)
{
char sqlstr[512] = {0};
char *errmsg, **result;
int nrow, ncolum;
//通过sqlite3_get_table函数查询记录是否存在
if (msg->type == 1)
{
sprintf(sqlstr, "select * from admin where aname = '%s' and pd = '%s'", msg->name, msg->passwd);
}
else if (msg->type == 2)
{
sprintf(sqlstr, "select * from employee where uname = '%s' and pd = '%s'", msg->name, msg->passwd);
}
if (sqlite3_get_table(db, sqlstr, &result, &nrow, &ncolum, &errmsg) != SQLITE_OK)
{
printf("登录失败error:%s\n", errmsg);
}
//通过nrow参数判断是否能够查询到记录,如果值为0,则查询不到,如果值为非0,则查询到
if (nrow == 0)
{
strcpy(msg->data, "名字或密码错误!!!");
send(acceptfd, msg, sizeof(msg_t), 0);
return -1;
}
else
{
strncpy(msg->data, "OK", 256);
send(acceptfd, msg, sizeof(msg_t), 0);
return 0;
}
}
//删除,只有管理员
void do_delete(int acceptfd, msg_t *msg, sqlite3 *db)
{
char buff[N] = {0};
char *errmsg, **result;
int nrow, ncolum;
sprintf(buff, "select * from employee where uname = '%s'", msg->name);
if (sqlite3_get_table(db, buff, &result, &nrow, &ncolum, &errmsg) != SQLITE_OK)
{
printf("遍历查询失败error: %s\n", errmsg);
}
if (nrow == 0)
{
strcpy(msg->data, "用户不存在");
}
memset(buff, 0, sizeof(buff));
sprintf(buff, "DELETE FROM employee WHERE uname='%s'", msg->name);
if (sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("删除失败error: %s\n", errmsg);
strcpy(msg->data,"删除失败");
}
strcpy(msg->data, "删除成功");
send(acceptfd, msg, sizeof(msg_t), 0);
sqlite3_free(errmsg);
sqlite3_free_table(result);
}
//修改,用户只能修改除薪资和职务以外的数据
void do_modify(int acceptfd, msg_t *msg, sqlite3 *db)
{
char buff[N] = {0};
char *errmsg;
if (msg->type == 1) //管理员
{
sprintf(buff, "UPDATE employee SET salary='%d',office='%s' WHERE uname='%s'", msg->salary, msg->office, msg->name);
}
else if (msg->type == 2)
{ //普通用户
sprintf(buff, "UPDATE employee SET age='%d',passwd='%s' WHERE uname='%s'", msg->age, msg->passwd, msg->name);
}
if (sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("修改失败error: %s\n", errmsg);
}
strcpy(msg->data, "修改成功");
printf("修改成功\n");
printf("%d %s\n",msg->age,msg->passwd);
send(acceptfd, msg, sizeof(msg_t), 0);
return;
}
//查询
void do_query(int acceptfd, msg_t *msg, sqlite3 *db)
{
char buff[N] = {0};
char *errmsg, **result;
int nrow = 0;
int ncolumn = 0;
int i = 0;
int j = 0;
if (msg->type == 1)
{ //管理员
sprintf(buff, "SELECT * FROM employee");
if (sqlite3_get_table(db, buff, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
{
printf("查询失败errmsg:%s\n", errmsg);
strcpy(msg->data, "查询失败");
send(acceptfd, msg, sizeof(msg_t), 0);
}
//输出表头
sprintf(msg->data2, "%10s%10s%10s%10s%10s", result[0], result[1], result[2], result[3], result[4]);
int index = 5;
sprintf(msg->data2 + strlen(msg->data2), "\n");
//输出各条记录各个字段的值
for (i = 0; i < nrow; i++)
{ // i控制查到的记录数,行数,不包括表头行
for (j = 0; j < ncolumn; j++)
{
sprintf(msg->data2 + strlen(msg->data2), "%10s", result[index++]);
}
sprintf(msg->data2 + strlen(msg->data2), "\n");
}
sprintf(msg->data2 + strlen(msg->data2), "\n");
strcpy(msg->data, "查询成功");
printf("查询成功\n");
send(acceptfd, msg, sizeof(msg_t), 0);
}else if(msg->type == 2){
sprintf(buff, "SELECT * FROM employee WHERE uname='%s'",msg->name);
if (sqlite3_get_table(db, buff, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
{
printf("查询失败errmsg:%s\n", errmsg);
strcpy(msg->data, "查询失败");
send(acceptfd, msg, sizeof(msg_t), 0);
}
int index = 0;
for (i = 0; i < nrow+1; i++)
{ // i控制查到的记录数,行数,不包括表头行
for (j = 0; j < ncolumn; j++)
{
sprintf(msg->data2 + strlen(msg->data2), "%10s", result[index++]);
}
sprintf(msg->data2 + strlen(msg->data2), "\n");
}
sprintf(msg->data2 + strlen(msg->data2), "\n");
strcpy(msg->data, "查询成功");
printf("查询成功\n");
send(acceptfd, msg, sizeof(msg_t), 0);
}
sqlite3_free_table(result);
sqlite3_free(errmsg);
}
客户端:
#include <head.h>
#define R 1 //用户注册
#define L 2 //用户登录
#define D 3 //删除
#define M 4 //修改
#define Q 5 //查询
#define N 512
typedef struct MSG
{
int type; // 1为管理员,2为普通用户
int type2; //用户选项
char name[16]; //管理员名字
char pd[128]; //密码或数据
int age;
int salary;
char data[N];
char data2[N];
char office[64];
int flag;
} msg_t;
void do_register(int, msg_t *);
int do_login(int, msg_t *);
void increase_msg(int, msg_t *);
void delete_msg(int, msg_t *);
void modify_msg(int, msg_t *);
void query_msg(int, msg_t *);
int main(int argc, const char *argv[])
{
if (argc != 3)
{
printf("Usage: %s <ip> <port>\n", argv[0]);
exit(-1);
}
//创建套接字
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
PRINT_ERR("socket error");
}
//填充服务器网络信息结构体
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = inet_addr(argv[1]);
client_addr.sin_port = htons(atoi(argv[2]));
socklen_t addrlen = sizeof(client_addr);
//与服务器建立连接
if (-1 == connect(sockfd, (struct sockaddr *)&client_addr, addrlen))
{
PRINT_ERR("connect error");
}
//创建表
msg_t msg;
int n = 0;
int m = 2;
//收发数据
while (1)
{
printf("**************************************\n");
printf("**************员工管理系统*************\n");
printf("******1.管理员 2.普通用户 3.退出******\n");
printf("**************************************\n");
printf("请选择: ");
scanf("%d", &n);
switch (n)
{
case 1:
memset(&msg, 0, sizeof(msg_t));
msg.type = R; //管理员
send(sockfd, &msg, sizeof(msg_t), 0);
goto SELECT;
break;
case 2:
msg.type = L; //普通用户
send(sockfd, &msg, sizeof(msg_t), 0);
goto SELECT;
break;
case 3:
close(sockfd);
exit(0);
default:
printf("输入有误,请重新输入\n");
}
}
SELECT:
while (1)
{
printf("**************************************\n");
printf("**************员工管理系统*************\n");
printf("*****1.注册 2.登录(%d次机会) 3.退出****\n", m);
printf("**************************************\n");
printf("请选择:");
scanf("%d", &n);
switch (n)
{
case 1:
do_register(sockfd, &msg);
goto SELECT;
break;
case 2:
m--;
if (1 == do_login(sockfd, &msg))
{ //登录成功
if (msg.type == 1) //管理员
{
goto ADMIN_LOGIN;
}
else if (msg.type == 2) //用户
{
goto LOGIN;
}
}
else
{ //登录失败
if (m == 0)
{
close(sockfd);
exit(0);
}
goto SELECT;
}
break;
case 3:
close(sockfd);
exit(0);
default:
printf("输入有误,请重新输入\n");
}
}
ADMIN_LOGIN:
while (1)
{
printf("*****************************管理员界面*********************************\n");
printf("**** * * * * *****\n");
printf("****1.增加员工信息 2.删除员工信息 3.修改员工信息 4.查询员工信息 5.退出****\n");
printf("***********************************************************************\n");
printf("请选择:");
scanf("%d", &n);
switch (n)
{
case 1:
increase_msg(sockfd, &msg);
msg.type == R;
goto ADMIN_LOGIN;
break;
case 2:
delete_msg(sockfd, &msg);
goto ADMIN_LOGIN;
break;
case 3:
modify_msg(sockfd, &msg);
goto ADMIN_LOGIN;
break;
case 4:
query_msg(sockfd, &msg);
goto ADMIN_LOGIN;
break;
case 5:
close(sockfd);
exit(0);
default:
printf("输入有误,请重新输入\n");
}
}
LOGIN:
while (1)
{
printf("*****************************用户界面*********************************\n");
printf("**** * * * * *****\n");
printf("****1.查询本人信息 2.修改本人信息 3.退出****\n");
printf("**********************************************************************\n");
printf("请选择:");
scanf("%d", &n);
switch (n)
{
case 1:
query_msg(sockfd, &msg);
memset(msg.data2,0,sizeof(msg.data2));
goto LOGIN;
break;
case 2:
modify_msg(sockfd, &msg);
break;
case 3:
close(sockfd);
exit(0);
default:
printf("输入有误,请重新输入\n");
}
}
//关闭套接字
close(sockfd);
return 0;
}
//注册
void do_register(int sockfd, msg_t *msg)
{
if (msg->type == 1)
{
msg->type2 = R;
printf("请输入你的用户名: ");
scanf("%s", msg->name);
printf("请输入你的密码:");
scanf("%s", msg->pd);
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
printf("%s\n", msg->data);
}
else if (msg->type == 2)
{
msg->type2 = R;
printf("请输入你的用户名: ");
scanf("%s", msg->name);
printf("请输入你的密码:");
scanf("%s", msg->pd);
printf("请输入你的年龄:");
scanf("%d", &(msg->age));
printf("请输入你的薪资:");
scanf("%d", &(msg->salary));
printf("请输入你的职务:");
scanf("%s", msg->office);
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
printf("%s\n", msg->data);
}
}
//登录
int do_login(int sockfd, msg_t *msg)
{
char name[16] = {0};
char pd[64] = {0};
msg->type2 = L;
printf("请输入名字:");
scanf("%s", name);
strcpy(msg->name, name);
printf("请输入密码:");
scanf("%s", pd);
strcpy(msg->pd, pd);
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
printf("msg.pd = %s\n", msg->pd);
//判断是否登录成功
if (strncmp(msg->data, "OK", 3) == 0)
{
//登录成功返回1
printf("登录成功\n");
return 1;
}
printf("%s\n", msg->data);
return 0;
}
//添加员工
void increase_msg(int sockfd, msg_t *msg)
{
char name[16];
char passwd[64];
int age;
int salary;
char office[64];
msg->type = L; //切换到用户
msg->type2 = R; //选项1,添加员工信息
printf("请输入要添加的员工的名字:");
scanf("%s", name);
strcpy(msg->name, name);
printf("请输入要添加员工的密码:");
scanf("%s", pd);
strcpy(msg->pd, pd);
printf("请输入要添加员工的年龄:");
scanf("%d", &age);
msg->age = age;
printf("请输入要添加员工的薪资:");
scanf("%d", &salary);
msg->salary = salary;
printf("请输入要添加员工的职务:");
scanf("%s", office);
strcpy(msg->office, office);
printf("msg.name = %s\n", msg->name); // admin
printf("msg.pd = %s\n", msg->pd); // 123
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
printf("%s\n", msg->data);
}
//删除员工
void delete_msg(int sockfd, msg_t *msg)
{
msg->type2 = D;
printf("请输入要删除的名字:");
scanf("%s", msg->name);
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
printf("%s\n", msg->data);
}
void modify_msg(int sockfd, msg_t *msg)
{
if (msg->type==1)
{
msg->type2 = M;
printf("请输入要修改信息的员工名字:");
scanf("%s", msg->name);
printf("请输入员工的薪资为:");
scanf("%d", &(msg->salary));
printf("请输入员工的职位为:");
scanf("%s", msg->office);
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
}else if(msg->type == 2){
msg->type2 = M;
printf("请输入你的名字:");
scanf("%s", msg->name);
printf("请输入要修改的年龄为:");
scanf("%d", &(msg->age));
printf("请输入要修改的密码为:");
scanf("%s", msg->pd);
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
}
printf("%s\n",msg->data);
}
void query_msg(int sockfd, msg_t *msg)
{
msg->type2 = Q;
send(sockfd, msg, sizeof(msg_t), 0);
recv(sockfd, msg, sizeof(msg_t), 0);
printf("%s\n", msg->data);
printf("%10s", msg->data2);
}