項目——網絡版ATM

網絡版ATM

在這裏插入圖片描述

設計結構體

#ifndef STRUCT_H
#define	STRUCT_H

//賬號結構體
typedef struct User
{
	//賬號
	int id;
	//密碼
	char password[7];
	//身份證號
	char ID[19];
	//金額
	double money;
	//鎖定標誌位
	int state;
	//在線標誌位
	int is_online;
}User;

//消息結構體
typedef struct Msg
{
	//消息類型
	long msg_type;
	//錯誤信息類型
	int error_type;
	//操作對象
	int object_id;
	//帳號結構體
	User user;
}Msg;

//ip地址操作對象結構體
typedef struct Fd_ip
{
	//fd標識符
	int fd;
	//fd所對應的ip地址
	char ip[20];
}Fd_ip;

#endif

客戶端

1、進入時的功能開戶、銷戶、登錄、解鎖
開戶:輸入姓名、身份證號、設置密碼,如果開戶成功,則服務器上保存一個賬號信號(一個賬號存一個文件,文件名建議是賬號)。
銷戶:輸入帳號、密碼,服務器詢問是否確認銷戶,如果確認則服務器刪除帳號文件,並記錄帳號。
登錄:輸入賬號、密碼,三次錯誤賬號鎖定。
解鎖:輸入賬號、身份證號解鎖。

2、登錄成功:存錢、取錢、轉賬、查詢、修改密碼
存錢:輸入存錢金額
取錢:輸入取錢金額
轉賬:目標帳號和要轉的金額
查詢:不需要輸入數據
修改密碼:輸入新密碼

客戶端主函數

#include"tool.h"

void sigint(int signum)
{	
	user_exit();
	puts("客戶端已關閉!");
	kill(getpid(),9);
}

//客戶端主界面
int main()
{
	signal(SIGINT,sigint);
	signal(SIGQUIT,sigint);
	//進度條
	loading();
	//創建通信連接	
	if(-1 == c_s_socket())
	{
		puts("服務器繁忙,請稍後重試...");
		return -1;
	}
	//客戶端主界面
	c_main();
}

功能函數(大部分函數都在其中)

頭文件
#ifndef TOOL_H
#define TOOL_H
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <getch.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <semaphore.h>
#include <pthread.h>
#include <signal.h>
#include "struct.h"
#define HTONS 1990
#define ADDR "192.168.1.13"
#define SIZE 10

//操作類型
#define CREATE 			100
#define LOGIN 			200
#define DELETE 			300
#define UNLOCK 			400
#define STORE 			500
#define TAKE 			600
#define TRANSFER 		700
#define SEARCH 			800
#define CHANGE			900
#define USER_EXIT		1000

//錯誤類型
#define CONNECT_FAILD	-1
#define NO_ERROR		0
#define ERROR_id    	1
#define ERROR_PASSWORD  2
#define	IS_ONLINE		3
#define id_LOCKED    	4
#define id_UNLOCKED    	5
#define ERROR_ID    	6
#define TOO_MORE    	7
#define NEW_EQULE_OLD	8

//loading
#define RED 	"\033[31m"  
#define GREEN 	"\033[32m"  
#define YELLOW 	"\033[33m"  
#define BLUE 	"\033[34m"  
#define PORPLE 	"\033[35m"  
#define DGREEN 	"\033[36m"  

Msg c_msg;
int ask;
int answer;
int sockfd;
Fd_ip fd_ip[SIZE];
pid_t pids[9];

//********************************* 公共函數 ********************************
//進度條
void loading(void);
//清理緩衝區
void clear_stdin(void);
//任意鍵返回
void anykey_continue(void);
//提示信息
void show_msg(char* msg,int sec,int color);
//輸入函數
char* get_str(char* str,size_t size);
//密碼輸入
void password_input(char* str);
//密碼規則
int password_rule(char *str);
//打開消息隊列
void create_msglist(void);

//********************************* 客戶端函數 C ********************************
//客戶端主界面
int c_main(void);
//登錄成功 用戶操作界面
int client_user(void);
//創建c to s通信連接
int c_s_socket(void);
//錯誤類型判斷顯示
int error_confirm(int error);
//註冊函數
int client_create(void);
//登錄
int client_login(void);
//銷戶
int client_delete(void);
//解鎖
int client_unlock(void);
//存錢
int user_store(void);
//取錢
int user_take(void);
//轉賬
int user_transfer(void);
//查詢
int user_search(void);
//修改密碼
int user_change(void);
//用戶退出
int user_exit(void);


//********************************* 服務端函數 S ********************************
//創建s to c通信連接
int s_c_socket(void);
//開啓各項服務
void open_serves(void);
//用戶子線程
void* start(void* p);
//客戶端斷開連接操作
int serve_exit(int fd);

#endif 

功能函數內容

#include "tool.h"

//***************************************** 公用函數 *******************************************
//進度條
void loading(void)
{
	char buf[101] = {};
	int i =0;
	char *ptr = "|/-\\";
	for(i = 0; i<101; i++)
	{
		if(i<20)		printf(RED);	
		else if(i<40)	printf(YELLOW);	
		else if(i<60)	printf(GREEN);	
		else if(i<80)	printf(DGREEN);	
		else if(i<90)	printf(BLUE);	
		else 			printf(PORPLE);	
		buf[i] = '=';
		printf("[%-100s][%%%d][%c]",buf,i,ptr[i%4]);
		fflush(stdout);
		usleep(100000);
		printf("\n");
		system("clear");
	}
	printf("\033[0m");
}

//清理緩衝區
void clear_stdin(void)
{	
	stdin->_IO_read_ptr=stdin->_IO_read_end;
}

//任意鍵返回
void anykey_continue(void)
{
	clear_stdin();
	show_msg("按任意鍵繼續......",1,2);
	getch();
}

//提示信息
void show_msg(char* msg,int sec,int color)
{	
	//紅
	if(0==color)
	printf("\n\033[01;31m%s\n\033[00m\n",msg);
	//綠	
	if(1==color)
	printf("\n\033[01;32m%s\n\033[00m\n",msg);
	//黃	
	if(2==color)
	printf("\n\033[01;33m%s\n\033[00m\n",msg);

	sleep(sec);
}


//輸入函數
char* get_str(char* str,size_t size)
{
	if(NULL == str) return str;
	clear_stdin();
	fgets(str,size,stdin);
	if(size-1 == strlen(str))
	{
		if('\n'==str[size-2])
			str[size-2]= '\0';
		else
			clear_stdin();
	}
	else
		str[strlen(str)-1]='\0';
}

//密碼輸入
void password_input(char* str)
{
	for(int i=0;i<7;i++)
	{
		str[i]=getch();
		if(i>0&&127 == str[i])
		{
			i-=2;
			printf("\b \b");
			continue;
		}
		if(127 == str[i])
		{
			i--;
			continue;
		}
		if('\n'==str[i])
		{
			str[i]='\0';
			break;
		}
		putchar('*');
		
	}
}

//密碼規則
int password_rule(char *str)
{
	int len=strlen(str);
	if(6!=len)
	return -1;
	for(int i=0;str[i];i++)
	{
		if(str[i]<'0' || str[i]>'9')
		return -1;
	}
	return 1;
}

//打開消息隊列
void create_msglist(void)
{
	key_t c_key = ftok(".",1); 
	key_t s_key = ftok(".",2); 
	ask = msgget(c_key,IPC_CREAT|00644);
	answer = msgget(s_key,IPC_CREAT|00644);
}

//***************************************** 客戶端函數  C ****************************************

//客戶端主界面
int c_main(void)
{
	while(1)
	{
		clear_stdin();
		system("clear");
		puts("-----客戶端主界面-----");
		puts("1.登錄");
		puts("2.註冊");
		puts("3.銷戶");
		puts("4.解鎖");
		puts("0.退出");
		clear_stdin();
		switch(getch())
		{
			case 49:if(1==client_login())client_user();break;
			case 50:client_create();break;
			case 51:client_delete();break;
			case 52:client_unlock();break;
			case 48:puts("客戶端已關閉!");return 0;
		}
	}
}


//登錄成功 用戶操作界面
int client_user(void)
{
	while(1)
	{
		clear_stdin();
		system("clear");
		puts("-----用戶界面-----");
		printf("賬戶ID:%d\n",c_msg.user.id);
		puts("-----------------");
		puts("1.存入現金");
		puts("2.取出現金");
		puts("3.轉賬操作");
		puts("4.查詢信息");
		puts("5.修改密碼");
		puts("0.退出登錄");
/*測試用信息
		printf("*msg type:%ld\n",c_msg.msg_type);
		printf("*error type:%d\n",c_msg.error_type);
		printf("*object_id;:%d\n",c_msg.object_id);
		printf("*賬戶ID:%d\n",c_msg.user.id);
		printf("*賬戶密碼:%s\n",c_msg.user.password);
		printf("*身份證號碼:%s\n",c_msg.user.ID);
		printf("*存款:%.2lf\n",c_msg.user.money);
		printf("*狀態:%d\n",c_msg.user.state);
		printf("*在線:%d\n",c_msg.user.is_online);
*/
		clear_stdin();
		switch(getch())
		{
			case 49:user_store();break;
			case 50:user_take();break;
			case 51:user_transfer();break;
			case 52:user_search();break;
			case 53:user_change();break;
			case 48:user_exit();return 0;
		}
	}
}

//創建c to s通信連接
int c_s_socket(void)
{
	//創建socket對象
	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(0>sockfd)
	{
		perror("socket");
		return -1;
	}
	//準備通信地址
	struct sockaddr_in addr ={};
	addr.sin_family = AF_INET;
	addr.sin_port = htons(HTONS);
	addr.sin_addr.s_addr = inet_addr(ADDR);

	//連接
	if(0>connect(sockfd,(struct sockaddr*)&addr,sizeof(addr)))
	{
		perror("connect");
		return -1;
	}
	//接收連接結果
	recv(sockfd,&c_msg,sizeof(Msg),0);
	if(1 == error_confirm(c_msg.error_type))
	{
		show_msg("連接成功!",1,1);
		return 1;
	}
	return -1;
		
	
}

//錯誤類型判斷顯示
int error_confirm(int error)
{
	switch(error)
	{
		case NO_ERROR:		return 1;
		case CONNECT_FAILD:	show_msg("連接失敗!",2,0);				break;
		case ERROR_id:		show_msg("賬號不存在!",2,0);				break;
		case ERROR_PASSWORD:show_msg("密碼錯誤!",2,0);				break;
		case IS_ONLINE:		show_msg("賬號已在某處登錄!若非本人操作請詢問工作人員或撥打 110 報警",3,0);	break;
		case id_LOCKED:		show_msg("賬號已鎖定!",2,0);				break;
		case id_UNLOCKED:	show_msg("賬號未被鎖定!",2,0);			break;
		case ERROR_ID:		show_msg("身份證號碼錯誤!",2,0);			break;
		case TOO_MORE:		show_msg("無法提供該金額!",2,0);			break;
		case NEW_EQULE_OLD:	show_msg("錯誤:新密碼與舊密碼一致!",2,0);	break;
	}
	c_msg.error_type=NO_ERROR;
	return -1;
}

//註冊函數
int client_create(void)
{	
	//操作類型
	c_msg.msg_type = CREATE;
	clear_stdin();
	system("clear");
	printf("-----用戶開戶-----\n");
	clear_stdin();
	printf("請輸入身份證號:");
	get_str(c_msg.user.ID,18);
	printf("請輸入6位密碼:");
	char buf[7]={};
	password_input(buf);
	if(-1 == password_rule(buf))
	{
		show_msg("密碼格式錯誤...",1,0);
		return -1;
	}
	//確認新密碼
	printf("\n請再次輸入密碼:");
	password_input(c_msg.user.password);

	//兩次輸入不一致,退出
	if( 0 != strcmp(buf,c_msg.user.password))
	{
		show_msg("錯誤:兩次輸入的密碼不一致!",1,0);
		anykey_continue();
		return -1;
	}
	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);
	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);
	show_msg("註冊成功!",1,1);
	printf("您的賬號爲:=%d\n",c_msg.user.id);
	anykey_continue();
}

//登錄函數
int client_login(void)
{
	//操作類型
	c_msg.msg_type = LOGIN;
	clear_stdin();
	system("clear");
	printf("-----用戶登錄-----\n");
	clear_stdin();
	printf("請輸入賬號:");
	scanf("%d",&c_msg.user.id);
	clear_stdin();
	printf("請輸入密碼:");
	password_input(c_msg.user.password);
	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);

	//錯誤判斷//return 1 才能進入用戶界面
	if(1 == error_confirm(c_msg.error_type))
	{
		show_msg("登錄成功!",1,1);
		return 1;
	}
	return -1;
}

//銷號
int client_delete(void)
{
	//操作類型
	c_msg.msg_type = DELETE;
	clear_stdin();
	system("clear");
	printf("-----賬號銷號-----\n");
	clear_stdin();
	printf("請輸入要銷號的賬號:");
	scanf("%d",&c_msg.user.id);
	clear_stdin();
	printf("請輸入密碼:");
	password_input(c_msg.user.password);

	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);

	//錯誤判斷
	if(1 == error_confirm(c_msg.error_type))
	{	
		if(0 < c_msg.user.money)
		{
			show_msg("賬戶中還有餘額,正在退還餘額!",2,1);
			printf("退還餘額 %.2lf 元,請收好您的鈔票。\n",c_msg.user.money);
			sleep(2);		
		}
		show_msg("銷戶成功!",2,1);
		return 1;
	}
	return -1;
	
}

//解鎖
int client_unlock(void)
{
	//操作類型
	c_msg.msg_type = UNLOCK;
	clear_stdin();
	system("clear");
	printf("-----解鎖賬號-----\n");
	clear_stdin();
	printf("請輸入要解鎖的賬號:");
	scanf("%d",&c_msg.user.id);
	clear_stdin();
	printf("請輸入身份證號:");
	get_str(c_msg.user.ID,20);

	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);

	//錯誤判斷
	if(1 == error_confirm(c_msg.error_type))
	{	
		show_msg("解鎖成功!",1,1);
		printf("您的密碼爲:%s\n",c_msg.user.password);
		anykey_continue();
		return 1;
	}
	return -1;	
}

//存錢
int user_store(void)
{
	//操作類型
	c_msg.msg_type = STORE;
	clear_stdin();
	system("clear");
	printf("-----存入現金-----\n");
	clear_stdin();
	double sum=0;
	printf("請輸入要存入的金額:");
	scanf("%lf",&sum);
	if(0 >= sum)
	{
		show_msg("不能存入零或小於零的金額!",1,0);
		return -1;
	}
	c_msg.user.money = sum;
	clear_stdin();
	show_msg("請把現金放入存鈔口",1,2);
	anykey_continue();

	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);
	show_msg("正在存鈔請稍後...",1,2);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);
	
	show_msg("操作已成功!",1,1);	
	printf("您的餘額爲:%.2lf\n",c_msg.user.money);
	anykey_continue();	
}

//取錢
int user_take(void)
{
	//操作類型
	c_msg.msg_type = TAKE;
	clear_stdin();
	system("clear");
	printf("-----取出現金-----\n");

	double sum=0;
	clear_stdin();
	printf("請輸入要取出的金額:");
	scanf("%lf",&sum);
	if(0 >= sum)
	{
		show_msg("不能存入零或小於零的金額!",1,0);
		return -1;
	}
	c_msg.user.money = sum;

	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);
	show_msg("正在取出現金請稍後...",1,2);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);
	
	//錯誤判斷
	if(1 == error_confirm(c_msg.error_type))
	{	
		show_msg("操作已成功!",1,1);	
		printf("您的餘額爲:%.2lf\n",c_msg.user.money);
		show_msg("請取走您的現金!",2,3);
		return 1;
	}
	return -1;
}

//轉賬
int user_transfer(void)
{
	//操作類型
	c_msg.msg_type = TRANSFER;
	clear_stdin();
	system("clear");
	printf("-----轉賬-----\n");

	clear_stdin();
	printf("請輸入要轉賬的賬戶賬號:");
	scanf("%d",&c_msg.object_id);
	if(c_msg.object_id == c_msg.user.id)
	{
		show_msg("不能給自己轉賬!",1,0);
		return -1;
	}
	double sum=0;
	clear_stdin();
	printf("請輸入要轉賬的金額:");
	scanf("%lf",&sum);
	if(0 >= sum)
	{
		show_msg("不能存入零或小於零的金額!",1,0);
		return -1;
	}
	c_msg.user.money = sum;

	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);
	show_msg("正在轉賬請稍後...",1,2);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);

	//錯誤判斷
	if(1 == error_confirm(c_msg.error_type))
	{	
		show_msg("轉賬已成功!",1,1);	
		printf("您的餘額爲:%.2lf\n",c_msg.user.money);
		anykey_continue();
		return 1;
	}
	return -1;

}


//查詢
int user_search(void)
{
	//操作類型
	c_msg.msg_type = SEARCH;
	clear_stdin();
	system("clear");
	printf("-----查詢信息-----\n");

	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);

	//錯誤判斷
	if(1 == error_confirm(c_msg.error_type))
	{	
		printf("*賬戶ID:%d\n",c_msg.user.id);
		printf("*身份證號碼:%s\n",c_msg.user.ID);
		printf("*存款:%.2lf\n",c_msg.user.money);
		anykey_continue();
		return 1;
	}
	return -1;
}

//修改密碼
int user_change(void)
{
	//操作類型
	c_msg.msg_type = CHANGE;
	clear_stdin();
	system("clear");
	printf("-----修改密碼-----\n");
	clear_stdin();
	
	//第一次輸入新密碼
	clear_stdin();
	printf("請輸入新密碼:");
	char buf[7]={};
	password_input(buf);
	//判斷密碼是否爲6位數
	if(-1 == password_rule(buf))
	{
		show_msg("密碼格式錯誤...",1,0);
		return -1;
	}
	//確認新密碼
	printf("\n請再次輸入新密碼:");
	password_input(c_msg.user.password);

	//兩次輸入不一致,退出
	if( 0 != strcmp(buf,c_msg.user.password))
	{
		show_msg("兩次輸入的密碼不一致!",1,0);
		anykey_continue();
		return -1;
	}

	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);
	show_msg("修改密碼中請稍後...",1,2);

	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);

	//錯誤判斷
	if(1 == error_confirm(c_msg.error_type))
	{	
		show_msg("修改成功!",1,1);
		printf("您的新密碼爲:%s\n",c_msg.user.password);
		anykey_continue();
		return 1;
	}
	return -1;
	
}

//用戶退出
int user_exit(void)
{
	//操作類型
	c_msg.msg_type = USER_EXIT;
	//向服務端發送信息
	send(sockfd,&c_msg,sizeof(Msg),0);
	//從服務端獲取數據
	recv(sockfd,&c_msg,sizeof(Msg),0);
	show_msg("成功退出!",1,1);
}

//***************************************** 服務端函數  S ****************************************


//創建s to c通信連接
int s_c_socket(void)
{
	Msg s_msg={};
	// 創建socket對象
	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(0 > sockfd)
	{
		perror("socket");
		return -1;
	}
	// 準備通信地址
	struct sockaddr_in addr = {};
	addr.sin_family = AF_INET;
	addr.sin_port = htons(HTONS);
	addr.sin_addr.s_addr = inet_addr(ADDR);

	// 綁定socket對象與通信地址
	socklen_t len = sizeof(addr);
	if(0 > bind(sockfd,(struct sockaddr*)&addr,len))
	{
		perror("bind");
		return -1;
	}

	// 設置監聽socket對象
	listen(sockfd,SIZE);

	// 等待連接
	while(1)
	{
		struct sockaddr_in from_addr;
		int user_fd = accept(sockfd,(struct sockaddr*)&from_addr,&len);
		if(0 > user_fd)
		{
			printf("客戶端連接出錯...\n");
			continue;
		}
		int i;
        for (i=0;i<SIZE;i++)
		{
            if (fd_ip[i].fd == 0)
			{
                //記錄客戶端的fd和ip
                fd_ip[i].fd = user_fd;
				strcpy(fd_ip[i].ip,inet_ntoa(from_addr.sin_addr));

				//線程id
				pthread_t pid;
				//線程屬性
				pthread_attr_t attr; 
				//初始化線程屬性
				pthread_attr_init(&attr);  
				//設置線程屬性
				pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
				//創建子線程      
				pthread_create(&pid,&attr,start,&user_fd);
				//提示連接成功
				s_msg.error_type = NO_ERROR;
				send(user_fd,&s_msg,sizeof(Msg),0);
				printf("客戶端:%s連接成功!\n",fd_ip[i].ip);
                break;
			}
        }
		if (SIZE == i)
		{
            //服務器滿了,關閉fd
			s_msg.error_type = CONNECT_FAILD;
			send(user_fd,&s_msg,sizeof(Msg),0);
            puts("服務器已滿");
            close(user_fd);
        }

    }
}

//用戶子線程
void* start(void* p)
{
	
	int fd =*(int*)p;
	Msg s_msg={};
	// 收發數據
	while(1)
	{
		//接受信息
 		if(0 >= recv(fd,&s_msg,sizeof(Msg),0))
		{
			//服務器退出關閉fd
			serve_exit(fd);
			//結束線程
           	pthread_exit(0);
		}
		
		//向服務端發送信息
		msgsnd(ask,&s_msg,sizeof(Msg)-4,0);
		
		//從服務端接受信息
		msgrcv(answer,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		send(fd,&s_msg,sizeof(Msg),0);	
		
	}	

}

//開啓各項服務
void open_serves(void)
{
	//登錄
	pid_t pid0=vfork();
	if(0 == pid0)
		execl("./login","login",NULL);
	else
	{
		perror("vfork login");
		pids[0]=pid0;
	}
	//開戶
	pid_t pid1=vfork();
	if(0 == pid1)
		execl("./create","create",NULL);
	else
	{
		perror("vfork create");
		pids[1]=pid1;
	}
	//銷戶
	pid_t pid2=vfork();
	if(0 == pid2)
		execl("./delete","delete",NULL);
	else
	{
		perror("vfork delete");
		pids[2]=pid2;
	}
	//解鎖
	pid_t pid3=vfork();
	if(0 == pid3)
		execl("./unlock","unlock",NULL);
	else
	{
		perror("vfork unlock");
		pids[3]=pid3;
	}
	//存錢
	pid_t pid4=vfork();
	if(0 == pid4)
		execl("./store","store",NULL);
	else
	{
		perror("vfork store");
		pids[4]=pid4;
	}
	//取錢
	pid_t pid5=vfork();
	if(0 == pid5)
		execl("./take","take",NULL);
	else
	{
		perror("vfork take");
		pids[5]=pid5;
	}
	//轉賬
	pid_t pid6=vfork();
	if(0 == pid6)
		execl("./transfer","transfer",NULL);
	else
	{
		perror("vfork transfer");
		pids[6]=pid6;
	}
	//查詢
	pid_t pid7=vfork();
	if(0 == pid7)
		execl("./search","search",NULL);
	else
	{
		perror("vfork search");
		pids[7]=pid7;
	}
	//修改密碼
	pid_t pid8=vfork();
	if(0 == pid8)
		execl("./change","change",NULL);
	else
	{
		perror("vfork change");
		pids[8]=pid8;
	}
	//退出登錄
	pid_t pid9=vfork();
	if(0 == pid9)
		execl("./logout","logout",NULL);
	else
	{
		perror("vfork logout");
		pids[9]=pid9;
	}
}

//客戶端斷開連接操作
int serve_exit(int fd)
{
	printf("進行退出\t");
    //退出後將位置空出來
    for (int i=0;i<SIZE;i++)
	{
    	if (fd == fd_ip[i].fd)
		{
            fd_ip[i].fd = 0;
			close(fd);
			printf("%s 退出成功\n",fd_ip[i].ip);
            break;
        }
    }
	
}

服務端

1、根據消息的類型識別客戶端請求的功能。
2、開啓服務各項功能的子進程
3、各進程按照消息類型接收消息

服務端主函數

#include"tool.h"

void sigint()
{
	printf("\n服務端所有進程已經關閉\n");
	msgctl(ask,IPC_RMID,NULL);
	msgctl(answer,IPC_RMID,NULL);
	for(int i=0;i<9;i++)
	{
		kill(pids[i],9);
	}
	close(sockfd);
	exit(0);
	
}

int main()
{
	puts("服務器已開啓");
	signal(SIGINT,sigint);
	signal(SIGQUIT,sigint);
	//開啓各項服務
	open_serves();
	//創建消息隊列
	create_msglist();
	//創建連接
	s_c_socket();
	//關閉進程
	sigint();
	
}

功能進程函數

註冊

#include"tool.h"

//服務端註冊操作
int main()
{
	Msg s_msg={CREATE};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行註冊\t");
		//打開計數文件
		int count_fd=open("users/count",O_RDWR|O_CREAT,00644);
		if(0 > count_fd)
		{
			perror("open user_ifo");
			continue;
		}
		int count=0;
		//讀取數量
		read(count_fd,&count,sizeof(int));
		//計數+1
		count++;
		//文件指針調到頭
		lseek(count_fd,0,SEEK_SET);
		//保存數量
		write(count_fd,&count,sizeof(int));
		
		close(count_fd);
	
		//給予id	
		s_msg.user.id=10000+count;
	
		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR|O_CREAT,00644);
		if(0 > fd)
		{
			perror("open user_ifo");
			continue;
		}
		
		//保存用戶信息
		write(fd,&s_msg.user,sizeof(User));
		close(fd);
		
		//發送答覆信息
		msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
		puts("註冊成功");
	}
}


登錄

#include"tool.h"

//服務端登錄操作
int main()
{	
	//printf("login pid=%d\n",getpid());
	Msg s_msg={LOGIN};
	Msg true_msg={LOGIN};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		true_msg.error_type = NO_ERROR;
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行登錄\t");

		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		//從文件中讀取客戶信息
		read(fd,&true_msg.user,sizeof(User));

		if(1 == true_msg.user.is_online)
		{
			puts("賬號已登錄!");
			//發送錯誤信息
			s_msg.error_type = IS_ONLINE;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fd);
			continue;
		}
		if(2 < true_msg.user.state)
		{
			puts("賬戶被鎖定!");
			//發送錯誤信息
			s_msg.error_type = id_LOCKED;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fd);
			continue;		
		}
		if(0 != strcmp(s_msg.user.password,true_msg.user.password))
		{
			puts("密碼錯誤!");
			true_msg.user.state ++;
			lseek(fd,0,SEEK_SET);
			write(fd,&true_msg.user,sizeof(User));
			close(fd);
			//發送錯誤信息
			s_msg.error_type = ERROR_PASSWORD;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		//登陸標誌設置爲 1 上線
		true_msg.user.is_online = 1;
		lseek(fd,0,SEEK_SET);
		write(fd,&true_msg.user,sizeof(User));
		close(fd);
		//發送答覆消息
		msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
		puts("登陸成功");	
	}
}

解鎖

#include "tool.h"

//服務端解鎖操作
int main()
{
	//printf("reset pid=%d\n",getpid());
	Msg s_msg={UNLOCK};
	Msg true_msg={UNLOCK};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行解鎖\t");
		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		
		read(fd,&true_msg.user,sizeof(User));
		if(3 > true_msg.user.state && 0 == true_msg.user.is_online)
		{
			puts("賬戶未被鎖定!");
			s_msg.error_type = id_UNLOCKED;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fd);	
			continue;	
		}
		if(0 != strcmp(s_msg.user.ID,true_msg.user.ID))
		{
			puts("身份證號碼錯誤!");
			s_msg.error_type = ERROR_ID;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fd);	
			continue;
		}
		if(1 == true_msg.user.is_online)
		{
			puts("賬號已在線!");
			s_msg.error_type=IS_ONLINE;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fd);
			continue;
		}
		//解鎖標誌位 置爲 0
		true_msg.user.state = 0;
		true_msg.user.is_online = 0;
		lseek(fd,0,SEEK_SET);
		write(fd,&true_msg.user,sizeof(User));
		close(fd);
		
		
		//發送答覆消息
		msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
		
		puts("解鎖成功");
	}
}


銷號

#include "tool.h"

//服務端銷號操作
int main()
{
	//printf("delete pid=%d\n",getpid());
	Msg s_msg={DELETE};
	Msg true_msg={DELETE};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行銷號\t");

		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type=ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		//從文件中讀取客戶信息
		
		read(fd,&true_msg.user,sizeof(User));
		
		if(0 != strcmp(s_msg.user.password,true_msg.user.password))
		{
			puts("密碼錯誤!");
			s_msg.error_type=ERROR_PASSWORD;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fd);
			continue;
		}
		
		if(1 == true_msg.user.is_online)
		{
			puts("賬號已在線!");
			s_msg.error_type=IS_ONLINE;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fd);
			continue;
		}
		//要刪除的賬戶id 轉換爲字符串
		char delete_buf[20]={};
		sprintf(delete_buf, "deleted/%d",s_msg.user.id);

		//刪除賬戶保存到另一文件夾
		int delete_fd=open(delete_buf,O_RDWR|O_CREAT,00644);
		if(0 > delete_fd)
		{
			perror("delete_fd");
		}
		write(delete_fd,&true_msg.user,sizeof(User));
		close(delete_fd);
		
		//發送答覆消息
		msgsnd(answer,&true_msg,sizeof(Msg)-4,0);

		//用戶餘額清零
		true_msg.user.money = 0;
		lseek(fd,0,SEEK_SET);
		write(fd,&true_msg.user,sizeof(User));
		close(fd);

		//刪除文件
		remove(buf);
		puts("銷號成功");
	}
		
}

存錢

#include "tool.h"

//服務端存錢操作
int main()
{
	//printf("store pid=%d\n",getpid());
	Msg s_msg={STORE};
	Msg true_msg={STORE};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		true_msg.error_type = NO_ERROR;
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行存錢\t");
		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		
		read(fd,&true_msg.user,sizeof(User));
		
		true_msg.user.money += s_msg.user.money;
		lseek(fd,0,SEEK_SET);
		write(fd,&true_msg.user,sizeof(User));
		close(fd);

		//向客戶端發送信息
		msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
		
		puts("存錢成功");
	}
	
}

取錢

#include "tool.h"

//服務端取錢操作
int main()
{
	//printf("take pid=%d\n",getpid());
	Msg s_msg={TAKE};
	Msg true_msg={TAKE};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		true_msg.error_type = NO_ERROR;
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行取錢\t");
		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		read(fd,&true_msg.user,sizeof(User));
		if(true_msg.user.money < s_msg.user.money)
		{
			puts("無法提供該金額!");
			true_msg.error_type = TOO_MORE;
			msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
			close(fd);
			continue;		
		}
		true_msg.user.money -= s_msg.user.money;
		lseek(fd,0,SEEK_SET);
		write(fd,&true_msg.user,sizeof(Msg));
		close(fd);
		
		//向客戶端發送信息
		msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
		
		puts("取錢成功");
	}
	
}

轉賬

#include "tool.h"

//服務端轉賬操作
int main()
{
	//printf("transfer pid=%d\n",getpid());
	Msg s_msg={TRANSFER};
	Msg truemsg_from={TRANSFER};
	Msg truemsg_to={TRANSFER};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		truemsg_from.error_type = NO_ERROR;
		truemsg_to.error_type = NO_ERROR;
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行轉賬\t");

		//賬戶ID 轉換爲字符串
		char buff[20]={};
		char buft[20]={};
		sprintf(buff, "users/%d",s_msg.user.id);
		sprintf(buft, "users/%d",s_msg.object_id);

		
		
		
		//buf:文件名爲賬戶id
		int fdf=open(buff,O_RDWR,00644);
		if(0 > fdf)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			close(fdf);
			continue;
		}
		read(fdf,&truemsg_from.user,sizeof(User));
		//printf("truemsg_from.user.money 1 =%lf\n",truemsg_from.user.money);
		//buft:轉賬賬戶文件
		int fdt=open(buft,O_RDWR,00644);
		if(0 > fdt)
		{	
			puts("轉賬賬戶不存在!");
			truemsg_from.error_type = ERROR_id;
			msgsnd(answer,&truemsg_from,sizeof(Msg)-4,0);
			close(fdt);
			continue;
		}
		read(fdt,&truemsg_to.user,sizeof(User));
		//轉賬金額大於存款 
		if(truemsg_from.user.money < s_msg.user.money)
		{
			puts("無法轉賬該金額!");
			truemsg_from.error_type = TOO_MORE;
			msgsnd(answer,&truemsg_from,sizeof(Msg)-4,0);
			close(fdf);
			close(fdt);
			continue;		
		}
		//轉賬賬戶 + 轉賬金額
		//本人賬戶 - 轉賬金額
		truemsg_to.user.money  += s_msg.user.money;
		truemsg_from.user.money -= s_msg.user.money;

		//printf("truemsg_from.user.money 2 =%lf\n",truemsg_from.user.money);
		//寫入兩個賬戶信息
		lseek(fdf,0,SEEK_SET);
		write(fdf,&truemsg_from.user,sizeof(User));
		close(fdf);

		lseek(fdt,0,SEEK_SET);
		write(fdt,&truemsg_to.user,sizeof(User));
		close(fdt);

		//向客戶端發送信息
		msgsnd(answer,&truemsg_from,sizeof(Msg)-4,0);
		
		puts("轉賬成功");
	}
	
}

查詢信息

#include "tool.h"

//服務端查詢操作
int main()
{
	//printf("search pid=%d\n",getpid());
	Msg s_msg = {SEARCH};
	//打開消息隊列
	create_msglist();
	while(1)
	{	
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("查詢信息\t");

		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		
		//從文件中讀取客戶信息
		read(fd,&s_msg.user,sizeof(User));
		close(fd);
		
		//向客戶端發送客戶信息
		msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
		puts("查詢成功");
	}
	
}

修改密碼

#include "tool.h"

//服務端存錢操作
int main()
{
	//printf("change pid=%d\n",getpid());
	Msg s_msg={CHANGE};
	Msg true_msg={CHANGE};
	//打開消息隊列
	create_msglist();
	while(1)
	{
		true_msg.error_type = NO_ERROR;
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("進行存錢\t");
		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		//從文件中讀取客戶信息
		read(fd,&true_msg.user,sizeof(User));
		
		if(0 == strcmp(true_msg.user.password,s_msg.user.password))	
		{	
			puts("新舊密碼一致!");
			true_msg.error_type = NEW_EQULE_OLD;
			msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
			close(fd);
			continue;
		}
		strcpy(true_msg.user.password,s_msg.user.password);
		//新密碼寫入文件
		lseek(fd,0,SEEK_SET);
		write(fd,&true_msg.user,sizeof(User));
		close(fd);
		
		//向客戶端發送客戶信息
		msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
		puts("修改密碼成功");
	}
	
}

退出登錄

#include "tool.h"

//服務端退出登錄操作
int main()
{
	//printf("logout pid=%d\n",getpid());
	Msg s_msg = {USER_EXIT};
	Msg true_msg = {USER_EXIT};
	//打開消息隊列
	create_msglist();
	while(1)
	{	
		true_msg.error_type = NO_ERROR;
		//接受請求信息
		msgrcv(ask,&s_msg,sizeof(Msg)-4,s_msg.msg_type,0);
		printf("退出登錄\t");

		//賬戶id 轉換爲字符串
		char buf[20]={};
		sprintf(buf, "users/%d",s_msg.user.id);

		//buf:文件名爲賬戶id
		int fd=open(buf,O_RDWR,00644);
		if(0 > fd)
		{
			puts("賬戶不存在!");
			s_msg.error_type = ERROR_id;
			msgsnd(answer,&s_msg,sizeof(Msg)-4,0);
			continue;
		}
		
		//從文件中讀取客戶信息
		read(fd,&true_msg.user,sizeof(User));
		
		true_msg.user.is_online = 0;
		
		//狀態寫入文件
		lseek(fd,0,SEEK_SET);
		write(fd,&true_msg.user,sizeof(User));
		close(fd);
		
		//向客戶端發送客戶信息
		msgsnd(answer,&true_msg,sizeof(Msg)-4,0);
		puts("退出登錄成功");
	}
	
}

Makefile

all:
	gcc -std=gnu99 -c tool.c
	gcc -std=gnu99 -c client.c
	gcc -std=gnu99 -c serve.c
	gcc -std=gnu99 -c create.c
	gcc -std=gnu99 -c login.c
	gcc -std=gnu99 -c delete.c
	gcc -std=gnu99 -c unlock.c
	gcc -std=gnu99 -c store.c
	gcc -std=gnu99 -c take.c
	gcc -std=gnu99 -c transfer.c
	gcc -std=gnu99 -c search.c
	gcc -std=gnu99 -c change.c
	gcc -std=gnu99 -c logout.c
	gcc -std=gnu99 create.c tool.c -o create -lpthread
	gcc -std=gnu99 login.c tool.c -o login -lpthread
	gcc	-std=gnu99 delete.c tool.c -o delete -lpthread
	gcc -std=gnu99 unlock.c tool.c -o unlock -lpthread
	gcc -std=gnu99 store.c tool.c -o store -lpthread
	gcc -std=gnu99 take.c tool.c -o take -lpthread
	gcc -std=gnu99 transfer.c tool.c -o transfer -lpthread
	gcc -std=gnu99 search.c tool.c -o search -lpthread
	gcc -std=gnu99 change.c tool.c -o change -lpthread
	gcc -std=gnu99 logout.c tool.c -o logout -lpthread
	gcc -std=gnu99 client.c tool.c -o client -lpthread
	gcc -std=gnu99 serve.c tool.c -o serve	-lpthread
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章