员工信息管理系统是基于Linux 多线程并发服务器编程,由服务器端和客户端构成,客户端可以运行在多个不同的主机上连接服务器,服务器对员工信息的操作结果通过“员工信息文件”来保存,即:“员工信息”存放在后台的文件中,相当于数据库。当用户登录后,根据用户名判断用户是否为管理员。如果为管理员,则进入管理员目录,如果为普通员工,则进入员工目录。在管理员目录,可以查看任意员工的信息,还可修改员工的信息,包括工资、评级,添加或删除用户。在员工目录,可以查看自己的信息,不能查看其他人的信息,可以修改自己的电话,地址等个人信息,但不能修改工资等管理员权限信息。
员工信息管理系统采用TCP协议,将在客户端采集的信息打包成结构体MSG,将MSG传送到服务器,服务器通过对MSG的解析,执行相关的操作,并把客户端请求的数据打包成结构体MSG发送给客户端,实现员工信息的管理。
(1) 客户端模块,通过对用户名的判断,判断用户是否为管理员,从而提供不同的接口,并将用户的请求打包为MSG结构体,发送给服务器。采用统一的结构体MSG在服务器与客户端进行信息交流,可以统一接口,方便信息分析。
(2)服务器模块,通过对结构体MSG的分析,对客户端的请求新建子进程来处理客户端的请求,实现多用户。
服务器端是员工和管理员的数据信息存储区。服务器负责通过判断客户端一系列请求,对数据做出相应的操作。
主要包含服务器通讯模块、服务器数据库处理模块。服务器端功能描述如下:
(1) 打开服务器:
打开服务器时,打开数据文件和网络通讯,并对网络进行监听。
(2) 收到客户端数据:
从服务器接受到数据后先判断登陆结构体是否有变化,如果有变化,表示有新用户登陆,则创建一个子进程,如果没有变化则表示无用户登陆或收到数据为已登录用户的数据。如果是用户登陆,则判断是否是管理员账户。通过接受客户端请求操作数据文件,完成后将结果发送给客户端,并返回等待下次的数据到来,如果出现错误,则发送错误信息给客户端。
员工和管理员通过客户端登陆后执行操作。不同的是在通过姓名验证的时候,系统会自动判断登陆者身份,以辨认是普通用户还是系统管理员。通过不同类别用户的登录从而实现不同的操作。普通用户有如下操作:查看和修改自身的信息。系统管理员有如下操作:查看所有用户信息及对用户信息的增,删,改,查。用户信息根据用户需求设定,初步设计包含员工编号,用户名,联系电话,住址,年龄,工资情况,员工评级七项。其中工资情况和员工评级为只有管理员权限可修改项。
客户端主要包括用户登录模块、用户权限选择模块、用户信息的操作请求模块和退出程序几部分。
(1)登录模块:连接上服务器之后进入登录模块,提示用户输入用户名和密码。如果用户名和密码正确则登录成功进入相应的界面,否则返回登录界面。
(2)用户权限选择模块:用户登录成功之后,经过服务器端判断决定用户进入对应权限的界面。
(3)用户信息操作模块:如果进入的是管理员界面则管理员过姓名选择相应的员工信息后,具有添加用户、删除用户、修改用户信息、查询用户信息四项权限。如果进入的时普通用户界面则该用户仅具有修改个人信息(包含修改密码)、查询用户信息两项权限。向服务器发送相应的请求,实现功能。
(4)退出程序:当用户操作结束之后退出程序,也可返回上一层目录。
服务器
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "head.h"
typedef struct sockaddr SA;
int Info_rmark = 0;//文件Info.text互斥操作的读
int Info_wmark = 0;//文件Info.text互斥操作的写
int User_rmark = 0;//文件User.text互斥操作的读
int User_wmark = 0;//文件User.text互斥操作的写
void findMsg(MSG *);
void findUser(MSG *);
void addMsg(MSG *);
void addUser(MSG *);
void delMsg(MSG *);
void delUser(MSG *);
void* handler(void * arg)//接收客户端消息,判断消息类型
{
MSG msg;
int n;
int connfd = (int)arg;
while(1)
{
n = recv(connfd,&msg, sizeof(MSG), 0);
printf("get message from %s type:%d sign:%d\n",msg.name,msg.type,msg.sign);
if(msg.type == QUIT)
{
printf("user %s quit!\n",msg.name);
pthread_exit(NULL);
close(connfd);
}
if(n == -1)
break;
if(msg.type == QUIT)
break;
getMsg(&msg);//取得客户端先要的信息,或者修改信息
printf("send message to %s type:%d sign:%d\n\n",msg.name,msg.type,msg.sign);
send(connfd,&msg, sizeof(MSG), 0);
}
close(connfd);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])//./server 127.0.0.1 10001
{
#if 0
USER user;
strcpy(user.name,"zx");
strcpy(user.passwd,"123");
user.type = 11;
user.no = 100;
FILE * fp = fopen("./user.dat","wb");
fwrite(&(user),sizeof(USER),1,fp);//写文件
fclose(fp);
#endif
int listenfd, connfd;
struct sockaddr_in ser_addr, cli_addr;
if(argc != 3)
{
printf("plz input %s \n", argv[0]);
exit(-1);
}
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
bzero(&ser_addr, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(atoi(argv[2]));//"10001"
ser_addr.sin_addr.s_addr = inet_addr(argv[1]);
if(bind(listenfd, (SA *)&ser_addr, sizeof(ser_addr)) == -1)
{
perror("bind");
exit(-1);
}
listen(listenfd, 5);
bzero(&cli_addr, sizeof(cli_addr));
socklen_t len = sizeof(cli_addr);
printf("listenfd = %d\n", listenfd);
while(1)//接受客户端请求,创建子线程
{
if((connfd = accept(listenfd, (SA *)&cli_addr, &len)) == -1)
{
perror("accept");
exit(-1);
}
printf("connect with ip : %s, port : %d\n",
inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
/*父进程接收客户端请求后,创建子进程与客户端通信*/
pthread_t child_pthread;
if(pthread_create(&child_pthread,NULL,handler,(void *)connfd) < 0)
{
perror("pthread_create");
exit(1);
}
}
close(listenfd);
return 0;
}
int getMsg(MSG * msg)//判断消息类型操作
{
switch(msg->type)
{
case READ:
findMsg(msg);
break;
case CHANGE:
delUser(msg);
addUser(msg);
delMsg(msg);
addMsg(msg);
break;
case ADD:
addUser(msg);
addMsg(msg);
break;
case DELETE:
delUser(msg);
delMsg(msg);
break;
case LOAD:
findUser(msg);
break;
default:
break;
}
return 0;
}
void findMsg(MSG *msg)//查找信息操作
{
INFO info_temp;
int flag = 0;
FILE *fp;
while(Info_wmark > 0) //实现读写文件的互斥
{
usleep(100000);
}
Info_rmark++;
if((fp = fopen("./info.dat","rb")) == NULL)
{
printf("User %s requset:no file info.dat\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
if(strcmp(msg->info.name,"null") != 0)//姓名不为空
{
while(fread(&info_temp,sizeof(INFO),1,fp) != 0)//读文件
{
if(strcmp(info_temp.name,msg->info.name) == 0)//比较名字是否相同
{
if(flag == 1)
{
if((msg->info.no != 0)&&(msg->info.no == info_temp.no))
{//存在另个名字一样的员工,则进行编号的对比
//如果一样则成功返回
msg->info = info_temp;
msg->sign = SUCCESS;
strcpy(msg->data,"find it");
return;
}
else
{
continue;//若编号不同则保留上一个员工信息
}
}
msg->sign = SUCCESS;
strcpy(msg->data,"find it");
msg->info = info_temp;
flag = 1;
}
}
if(flag == 0)
{
msg->sign = FAILED;
strcpy(msg->data,"not find");
return;
}
}
else if(msg->info.no != 0)
{
while(fread(&info_temp,sizeof(INFO),1,fp) != 0)//读文件
{
if(info_temp.no == msg->info.no)//比较编号是否相同
{
if(flag == 1)
{
if((strcmp(msg->info.name,"null") != 0)&&(strcmp(msg->info.name,info_temp.name) == 0))
{//存在另个编号一样的员工,则进行姓名的对比
msg->info = info_temp;
msg->sign = SUCCESS;
strcpy(msg->data,"find it");
return;
}
else
{
continue;//若姓名不同则保留上一个员工信息
}
}
msg->info = info_temp;
flag = 1;
}
}
if(flag == 0)
{
msg->sign = FAILED;
strcpy(msg->data,"not find");
return;
}
}
fclose(fp);
Info_rmark--;
}
void addMsg(MSG *msg)//添加信息操作
{
FILE * fp;
while((Info_wmark > 0)&&(Info_rmark > 0)) //实现读与写和读文件的互斥
{
usleep(100000);
}
Info_wmark++;
if((fp = fopen("./info.dat","ab")) == NULL)
{
printf("User %s requset:open Info.text failed\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
fwrite(&(msg->info),sizeof(INFO),1,fp) ;//写文件
printf("add info for %s ok!\n",msg->name);
msg->sign = SUCCESS;
strcpy(msg->data,"write info ok!\n");
fclose(fp);
Info_wmark--;
}
void delMsg(MSG *msg)//删除信息操作
{
FILE * fp;
int i = 0;
INFO info_temp[N];
while(Info_wmark > 0) //实现读与写和读文件的互斥
{
usleep(100000);
}
Info_rmark++;
if((fp = fopen("./info.dat","rb")) == NULL)
{
printf("User %s requset:open info.dat failed\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
while(fread(&(info_temp[i++]),sizeof(INFO),1,fp) != 0)//读文件
{
;
}
fclose(fp);
Info_rmark--;
//向文件中写数据
while((Info_wmark > 0)&&(Info_rmark > 0)) //实现读与写和读文件的互斥
{
usleep(100000);
}
Info_wmark++;
if((fp = fopen("./info.dat","wb")) == NULL)
{
printf("User %s requset:open info.dat failed\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
while(i--)
{
if(msg->info.no == info_temp[i].no)
continue;
fwrite(&(info_temp[i]),sizeof(INFO),1,fp);//写文件
}
printf("delete info for %s ok!\n",msg->name);
msg->sign = SUCCESS;
strcpy(msg->data,"change info ok!\n");
fclose(fp);
Info_wmark--;
}
void delUser(MSG *msg)//删除用户操作
{
FILE * fp;
int i = 0;
USER user_temp[N];
while(User_wmark > 0) //实现读与写和读文件的互斥
{
usleep(100000);
}
User_rmark++;
if((fp = fopen("./user.dat","rb")) == NULL)
{
printf("User %s requset:open user.dat failed\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
while(fread(&(user_temp[i++]),sizeof(USER),1,fp) != 0)//读文件
{
;
}
fclose(fp);
User_rmark--;
//向文件中写数据
while((User_wmark > 0)&&(User_rmark > 0)) //实现读与写和读文件的互斥
{
usleep(100000);
}
User_wmark++;
if((fp = fopen("./user.dat","wb")) == NULL)
{
printf("User %s requset:open user.dat failed\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
while(i--)
{
if(msg->info.no != user_temp[i].no)
fwrite(&(user_temp[i]),sizeof(USER),1,fp);//写文件
}
msg->sign = SUCCESS;
printf("delete user for %s ok !\n",msg->name);
strcpy(msg->data,"delete user ok!\n");
fclose(fp);
User_wmark--;
}
void findUser(MSG *msg)//查找用户操作
{
FILE * fp;
int flag = 0;
while(User_wmark > 0) //实现读与写和读文件的互斥
{
usleep(100000);
}
User_rmark++;
if((fp = fopen("./user.dat","rb")) == NULL)
{
printf("User %s requset:no file user.dat\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
USER user_temp;
while(fread(&user_temp,sizeof(USER),1,fp) != 0)//读文件
{
if(strcmp(user_temp.name,msg->name) == 0)//比较名字是否相同
{
if(strcmp(msg->passwd,user_temp.passwd) == 0)
{
flag = 1;
msg->sign = SUCCESS;
msg->info.type = user_temp.type;
msg->sign = SUCCESS;
strcpy(msg->data,"all is right");
return;
}
}
}
if(flag == 0)
{
msg->sign = FAILED;
strcpy(msg->data,"find user failed!\n");
return;
}
fclose(fp);
User_rmark--;
}
void addUser(MSG *msg)//添加用户操作
{
FILE * fp;
USER user;
strcpy(user.name,msg->info.name);
strcpy(user.passwd,msg->passwd);
user.type = STAFF;
user.no = msg->info.no;
while((User_wmark > 0)&&(User_rmark > 0)) //实现读与写和读文件的互斥
{
usleep(100000);
}
User_wmark++;
if((fp = fopen("./user.dat","ab")) == NULL)
{
printf("User %s requset:open user.dat failed\n",msg->name);
msg->sign = FAILED;
strcpy(msg->data,"not file");
return;
}
fwrite(&(user),sizeof(USER),1,fp);//写文件
printf("add user for %s ok!\n",msg->name);
msg->sign = SUCCESS;
strcpy(msg->data,"add user ok!\n");
fclose(fp);
User_wmark--;
}
客户端
#include
#include
#include
#include
#include
#include
#include
#include
#include "client.h"
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in serveraddr;
MSG msg;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(1);
}
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("connect");
exit(1);
}
while(1)
{
puts("------------------------------------");
puts("----------Login ^_^ ^_^-------------");
puts("------------------------------------");
/*
* 输入登录信息
*/
printf("please input your name >");
fgets(msg.name, N, stdin);
msg.name[strlen(msg.name) - 1] = '\0';
printf("please input your password >");
fgets(msg.passwd, N, stdin);
msg.passwd[strlen(msg.passwd) - 1] = '\0';
msg.type = LOAD;
send(sockfd, &msg, sizeof(MSG), 0);//发送消息给服务器,进行登录验证。
printf("---load type %d\n", msg.type);
recv(sockfd, &msg, sizeof(MSG), 0);//接收服务器的反馈消息。
if(msg.sign == FAILED)//登录失败
{
printf("%s\n", msg.data);
continue;
}
if(msg.sign == SUCCESS)//登录成功
{
if(msg.info.type == STAFF)
{
goto User;//进入普通用户界面
}
else if(msg.info.type == ADM)
{
goto Admin;// 进入管理员界面
}
}
}
/*普通用户界面*/
User:
while(1)
{
/*普通用户权限*/
puts("----------------------------------------------------");
puts("-------1: select info 2:modify passwd 3:exit --------");
puts("-----------------------------------------------------");
printf("please input you command >");
/*
*输入命令错误处理
*/
int command;
char clear[N];
if(scanf("%d",&command) == 0)
{
fgets(clear, N, stdin);
continue;
}
switch(command)
{
case 1:
msg.type = READ;
strcpy(msg.info.name , msg.name);
msg.info.no = 0;
send(sockfd, &msg, sizeof(MSG), 0);//发送查询消息
recv(sockfd, &msg, sizeof(MSG), 0);//接收服务器的反馈消息
printf(" ---------recv sign %d\n", msg.sign);
/*打印用户自身信息*/
printf("姓名 地址 年龄 级别\n");
printf("%s %s %d %d \n",msg.info.name, msg.info.addr, msg.info.age, msg.info.level);
printf("编号 工资 电话 用户类型\n");
printf("%d %lf %s %d \n",msg.info.no, msg.info.salary, msg.info.phone, msg.info.type);
break;
case 2:
getchar();
printf("please input your new password >");
getchar();
fgets(msg.passwd, N, stdin);
msg.passwd[strlen(msg.passwd) - 1] = '\0';
msg.type = CHANGE;
send(sockfd, &msg, sizeof(MSG), 0);//发送修改密码的消息
break;
case 3:
msg.type = QUIT;
send(sockfd, &msg, sizeof(MSG), 0);
goto Exit;//退出程序
}
}
/*管理员界面*/
Admin:
while(1)
{
/*管理员的权限*/
puts("--------------------------------------------------------------------");
puts("-----1:add user 2:delete user 3:modify info 4:select info 5:exit ----");
puts("---------------------------------------------------------------------");
printf("please input you command >");//输入对应的操作数字。
/*输入命令错误处理*/
int result;
int command;
char clear[N];
if(scanf("%d",&command) == 0)
{
fgets(clear, N, stdin);
continue;
}
switch(command)
{
case 1:
/*添加用户*/
do_adduser(sockfd, &msg);
if(result == SUCCESS)
{
puts("register OK");
}
else if(result == FAILED)
{
printf("%s\n", msg.data);
continue;
}
break;
case 2:
/*删除用户*/
result = do_deluser(sockfd, &msg);
if(result == SUCCESS)
{
puts("delete OK!");
}
else if(result == FAILED)
{
printf("%s\n", msg.data);
puts("failed to delete user");
continue;
}
break;
case 3:
/*修改用户信息*/
result = do_modifyuser(sockfd, &msg);
if(result == SUCCESS)
{
puts("success to modify !");
}
else if(result == FAILED)
{
printf("%s\n", msg.data);
puts("failed to modify!");
continue;
}
break;
case 4:
/*查询用户信息*/
result = do_selectuser( sockfd, &msg);
if( result == SUCCESS)
{
printf("姓名 地址 年龄 级别\n");
printf("%s %s %d %d \n",msg.info.name, msg.info.addr, msg.info.age, msg.info.level);
printf("编号 工资 电话 用户类型\n");
printf("%d %lf %s %d \n",msg.info.no, msg.info.salary, msg.info.phone, msg.info.type);
}
else if( result == FAILED)
{
printf("%s\n", msg.data);
puts("failed to select!");
continue;
}
break;
case 5:
msg.type = QUIT;
send(sockfd, &msg, sizeof(MSG), 0);
goto Exit;
}
}
Exit:
close(sockfd); //退出时关闭套接字
return 0;
}
/*添加用户*/
int do_adduser(int sockfd, MSG *msg)
{
printf("please input username >");
getchar();//清除垃圾字符
fgets((msg->info).name, N, stdin);
(msg->info).name[strlen((msg->info).name) - 1] = '\0';
printf("please input userpasswd >");
fgets(msg->passwd, N, stdin);
msg->passwd[strlen(msg->passwd) - 1] = '\0';
printf("please input useraddr >");
fgets((msg->info).addr, N, stdin);
(msg->info).addr[strlen((msg->info).addr) - 1] = '\0';
char clear[N];
input_age:
printf("please input userage >"); //输入类型不匹配时重新输入
if(scanf("%d",&(msg->info.age)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);//清理输入垃圾
goto input_age;
}
getchar();
input_level:
printf("please input userlevel >");
if(scanf("%d",&(msg->info.level)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_level;
}
getchar();
input_usrno:
printf("please input userno >");
if(scanf("%d",&(msg->info.no)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_usrno;
}
getchar();
input_salary:
printf("please input usersalary >");
if(scanf("%lf",&(msg->info.salary)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_salary;
}
getchar();
printf("please input userphone >");
fgets((msg->info).phone, N, stdin);
(msg->info).phone[strlen((msg->info).phone) - 1 ] = '\0';
input_usertype:
printf("please input usertype >");
if(scanf("%d", &(msg->info.type)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_usertype;
}
getchar();
msg->type = ADD;//发送个服务器的操作类型
/*
* 发送给服务器的结构体类型
* 必须和客户端的一致。
*/
send(sockfd, msg, sizeof(MSG), 0);
recv(sockfd, msg, sizeof(MSG), 0);
return msg->sign;// 返回服务器端的处理信息。
}
/*删除用户*/
int do_deluser(int sockfd, MSG *msg)
{
printf("please input username >");
getchar();
fgets((msg->info).name, N, stdin);
(msg->info).name[strlen((msg->info).name) - 1] = '\0';
printf("please input userno >");
if(scanf("%d", &(msg->info.no)) == 0)
{
msg->info.no = 0;
}
msg->type = DELETE;
send(sockfd, msg, sizeof(MSG) , 0);
recv(sockfd, msg, sizeof(MSG) , 0);
return msg->sign;// 返回服务器端的处理信息。
}
/*查询用户信息*/
int do_selectuser(int sockfd, MSG *msg)
{
printf("please input username >");
getchar();
fgets((msg->info).name, N, stdin);
(msg->info).name[strlen((msg->info).name) - 1] = '\0';
/*
* 当输入其他字符时,默认要查询的no的值为0。
*/
printf("please input userno >");
if(scanf("%d", &(msg->info.no)) == 0)
{
msg->info.no = 0;
}
msg->type = READ;//发送给服务器的操作类型。
send(sockfd, msg, sizeof(MSG) , 0);
recv(sockfd, msg, sizeof(MSG) , 0);
return msg->sign;// 返回服务器端的处理信息。
}
/*修改用户信息*/
int do_modifyuser(int sockfd, MSG *msg)
{
printf("please input username >");
getchar();
fgets((msg->info).name, N, stdin);
(msg->info).name[strlen((msg->info).name) - 1] = '\0';
printf("please input userpasswd >");
fgets(msg->passwd, N, stdin);
msg->passwd[strlen(msg->passwd) - 1] = '\0';
printf("please input useraddr >");
fgets((msg->info).addr, N, stdin);
(msg->info).addr[strlen((msg->info).addr) - 1] = '\0';
char clear[N];
input_age:
printf("please input userage >");
if(scanf("%d",&(msg->info.age)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_age;
}
getchar();
input_level:
printf("please input userlevel >");
if(scanf("%d",&(msg->info.level)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_level;
}
getchar();
input_usrno:
printf("please input userno >");
if(scanf("%d",&(msg->info.no)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_usrno;
}
getchar();
input_salary:
printf("please input usersalary >");
if(scanf("%lf",&(msg->info.salary)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_salary;
}
getchar();
printf("please input userphone >");
fgets((msg->info).phone, N, stdin);
(msg->info).phone[strlen((msg->info).phone) - 1 ] = '\0';
input_usertype:
printf("please input usertype >");
if(scanf("%d", &(msg->info.type)) == 0)
{
printf("the type error!\n");
fgets(clear, N, stdin);
goto input_usertype;
}
getchar();
msg->type = CHANGE;
send(sockfd, msg, sizeof(MSG), 0);
recv(sockfd, msg, sizeof(MSG), 0);
return msg->sign;// 返回服务器端的处理信息。
}
操作步骤
(1)执行命令gcc server.c -o server -lpthread生成可执行文件server。
(2)执行命令./server 127.0.0.1 10001,运行服务器端。
(3)执行命令gcc client.c -o client -lpthread生成可执行文件client。
(4)执行命令./client 127.0.0.1 10001,模拟客户1。
(5)执行命令./client 127.0.0.1 10001,模拟客户2。
(6)在客户端按下Ctrl+C,关闭客户连接。
当然也可写成Makefile文件直接编译
CC=gcc
CFLAGS=-Wall -g -O2 -lpthread
all:server client
server:server.o
$(CC) $< -o $@
client:client.o
$(CC) $< -o $@
%*.o:%*.c
$(CC) $(CFLAGS) $< -o $@
.PHONY:
clean
clean:
rm *.o server client
服务器
客户端1
客户端2