Linux多執行緒程式設計之員工資訊管理系統
員工資訊管理系統是基於Linux 多執行緒併發伺服器程式設計,由伺服器端和客戶端構成,客戶端可以執行在多個不同的主機上連線伺服器,伺服器對員工資訊的操作結果通過“員工資訊檔案”來儲存,即:“員工資訊”存放在後臺的檔案中,相當於資料庫。當用戶登入後,根據使用者名稱判斷使用者是否為管理員。如果為管理員,則進入管理員目錄,如果為普通員工,則進入員工目錄。在管理員目錄,可以檢視任意員工的資訊,還可修改員工的資訊,包括工資、評級,新增或刪除使用者。在員工目錄,可以檢視自己的資訊,不能檢視其他人的資訊,可以修改自己的電話,地址等個人資訊,但不能修改工資等管理員許可權資訊。
員工資訊管理系統採用TCP協議,將在客戶端採集的資訊打包成結構體MSG,將MSG傳送到伺服器,伺服器通過對MSG的解析,執行相關的操作,並把客戶端請求的資料打包成結構體MSG傳送給客戶端,實現員工資訊的管理。
(1) 客戶端模組,通過對使用者名稱的判斷,判斷使用者是否為管理員,從而提供不同的介面,並將使用者的請求打包為MSG結構體,傳送給伺服器。採用統一的結構體MSG在伺服器與客戶端進行資訊交流,可以統一介面,方便資訊分析。
(2)伺服器模組,通過對結構體MSG的分析,對客戶端的請求新建子程序來處理客戶端的請求,實現多使用者。
伺服器端
伺服器端是員工和管理員的資料資訊儲存區。伺服器負責通過判斷客戶端一系列請求,對資料做出相應的操作。
主要包含伺服器通訊模組、伺服器資料庫處理模組。伺服器端功能描述如下:
(1) 開啟伺服器:
開啟伺服器時,開啟資料檔案和網路通訊,並對網路進行監聽。
(2) 收到客戶端資料:
從伺服器接受到資料後先判斷登陸結構體是否有變化,如果有變化,表示有新使用者登陸,則建立一個子程序,如果沒有變化則表示無使用者登陸或收到資料為已登入使用者的資料。如果是使用者登陸,則判斷是否是管理員賬戶。通過接受客戶端請求操作資料檔案,完成後將結果傳送給客戶端,並返回等待下次的資料到來,如果出現錯誤,則傳送錯誤資訊給客戶端。
員工客戶端
員工和管理員通過客戶端登陸後執行操作。不同的是在通過姓名驗證的時候,系統會自動判斷登陸者身份,以辨認是普通使用者還是系統管理員。通過不同類別使用者的登入從而實現不同的操作。普通使用者有如下操作:檢視和修改自身的資訊。系統管理員有如下操作:檢視所有使用者資訊及對使用者資訊的增,刪,改,查。使用者資訊根據使用者需求設定,初步設計包含員工編號,使用者名稱,聯絡電話,住址,年齡,工資情況,員工評級七項。其中工資情況和員工評級為只有管理員許可權可修改項。
客戶端主要包括使用者登入模組、使用者許可權選擇模組、使用者資訊的操作請求模組和退出程式幾部分。
(1)登入模組:連線上伺服器之後進入登入模組,提示使用者輸入使用者名稱和密碼。如果使用者名稱和密碼正確則登入成功進入相應的介面,否則返回登入介面。
(2)使用者許可權選擇模組:使用者登入成功之後,經過伺服器端判斷決定使用者進入對應許可權的介面。
(3)使用者資訊操作模組:如果進入的是管理員介面則管理員過姓名選擇相應的員工資訊後,具有新增使用者、刪除使用者、修改使用者資訊、查詢使用者資訊四項許可權。如果進入的時普通使用者介面則該使用者僅具有修改個人資訊(包含修改密碼)、查詢使用者資訊兩項許可權。向伺服器傳送相應的請求,實現功能。
(4)退出程式:當用戶操作結束之後退出程式,也可返回上一層目錄。
原始碼
伺服器
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
#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 <ip> <port>\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 <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#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 [email protected]
client:client.o
$(CC) $< -o [email protected]
%*.o:%*.c
$(CC) $(CFLAGS) $< -o [email protected]
.PHONY:
clean
clean:
rm *.o server client
伺服器
客戶端1
客戶端2