1. 程式人生 > >銀行業務系統(c/s架構、socket網路程式設計、多執行緒)

銀行業務系統(c/s架構、socket網路程式設計、多執行緒)

1、功能要求

包括兩類使用者:管理人員和普通使用者(本文只寫了普通使用者程式)

普通使用者功能:登入登出、存取款、轉賬、查詢餘額

2、技術要求

要求用到多程序多執行緒

要求同時允許多個使用者操作(因為沒有註冊賬號功能,且只初始化了兩個賬號資訊,所以同時只能允許兩個賬號線上)

3、程式編寫

第一次寫C/S架構的程式,很多可能對於其他人來說很簡單的問題我之前都沒遇到過,所以寫的過程中充滿了艱辛,主要有幾個問題讓我困擾好久:

(1)客戶端伺服器之間的通訊,整個socket框架借鑑的網上其他人的部落格內容;

(2)技術要求中寫道要用多程序多執行緒,一開始以為兩個技術都要用到,糾結了老半天,網上查資料才明白選擇一種應該就可以了,好像是因為兩個技術同時使用容易出問題,具體也不太明白,我這裡使用的多執行緒,需要注意的是線上程函式中傳遞引數的問題,具體可看程式或網上其他分析;

(3)socket程式設計客戶端和伺服器之間收發資料時,send和recv函式都是傳送的一個數據緩衝區(const char FAR *buf),而銀行系統中根據不同的操作,傳送的資料型別和個數是不一樣的,根據網上資料,本文將所有要傳送或接受的資料定義在一個結構體中(分別是sendMsg和recvMsg),傳送的時候可以直接傳送結構體地址資訊(sendMsg),且因為資料緩衝區(buf)傳送的是字串,最後一個字元為'\o',所以傳送端的大小必須為(sizeof(sMsg)+1);在接收資料時,只能將接收到的資料存放在資料緩衝區(buf)中,然後再通過memcpy函式將其轉換成對應的結構體(recvMsg),需要注意的是客戶端和伺服器中的結構體名稱雖然可以不一樣,但是兩個結構體中對應的變數位置一定要相同,因為在傳送和接收的時候,memcpy函式只把資料解析到對應位置。

伺服器 server.c

#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <pthread.h>


#define SERVER_PORT 8888 //埠號,定義為巨集方便以後直接修改
#define BACKLOG     10   //表伺服器可以同時監測多少個客戶端連線,設定為>0即可


struct accountMsg
{
	//char *name;
	int password;
	int account;
	int balance;//餘額
	//bool uCal;//賬戶型別
};
	
struct accountMsg accountMsg1[10];


struct recvMsg
{
	//char *name;			//戶主姓名
	int account;		//賬號
	int password;		//密碼
	int money;		    //金額
	int uCal;			//賬戶型別
	int taskID;			//操作任務型別
	
};

//—————————————————————————登入驗證—————————————————————————————
int login(int iSocketClient,struct recvMsg rMsg)
{
	int iSendLen;
	int iRecvLen;
	int accessBuf=0;
	printf("____________login ing__________\n");
	int uid;
	for(uid=0;uid<10;uid++)

	{
		if(rMsg.account == accountMsg1[uid].account 
			&& rMsg.password == accountMsg1[uid].password )
		{
			accessBuf = 1;
			break;
		}
	}
	if (accessBuf !=1)
	{
		printf("__________login failed__________\n\n");
	}
	iSendLen = send(iSocketClient, &accessBuf, sizeof(accessBuf), 0);
	if (iSendLen <= 0)
	{
		printf("__________message zend error__________\n\n");
		close(iSocketClient);
		return -1;
	}
	if(accessBuf == 1)
	{
		printf("__________client login succeed!__________\n\n");
		accessBuf=0;
	}
	return uid;
}

//——————————————————————————存錢——————————————————————————
int saveMoney(int iSocketClient,struct recvMsg rMsg,int uid)
{
	printf("___________save Money ing__________\n");
	int iSendLen;
	accountMsg1[uid].balance = accountMsg1[uid].balance + rMsg.money;
	iSendLen = send(iSocketClient, &accountMsg1[uid].balance, sizeof(accountMsg1[uid].balance), 0);
	if (iSendLen <= 0)
	{
		printf("___________save Money failed__________\n\n");
		close(iSocketClient);
		return -1;
	}
	printf("___________save Money succeed__________\n\n");
	return 0;
}

//——————————————————————————取錢—————————————————————————————
int withdrawMoney(int iSocketClient,struct recvMsg rMsg,int uid)
{
	printf("___________withdraw Money ing__________\n");
	int iSendLen;
	int balance;
	balance = accountMsg1[uid].balance - rMsg.money;
	iSendLen = send(iSocketClient, &balance, sizeof(balance), 0);
	if (iSendLen <= 0)
	{
		printf("___________withdraw Money failed__________\n\n");
		close(iSocketClient);
		return -1;
	}
	else if(balance >= 0)
	{
		accountMsg1[uid].balance = balance;
	}
	printf("___________withdraw Money END__________\n\n");
	return 0;
}

//——————————————————————————轉賬—————————————————————————————
int transferMoney(int iSocketClient,struct recvMsg rMsg,int uid)
{
	printf("___________transfer Money ing__________\n");
	int iSendLen;
	int balance;
	balance = accountMsg1[uid].balance - rMsg.money;
	int tuid;
	for(tuid=0;tuid<10;tuid++)

	{
		//核對轉賬賬號是否存在
		if(rMsg.account == accountMsg1[tuid].account && tuid != uid)
		{	
			break;
		}
	}
	//賬號不存在
	if(tuid>=10)
	{
		printf("__________account do not exit_________\n\n");
		balance = -1;
	}
	iSendLen = send(iSocketClient, &balance, sizeof(balance), 0);
	if (iSendLen <= 0)
	{
		printf("___________transfer Money failed__________\n\n");
		close(iSocketClient);
		return -1;
	}
	else if(balance >= 0 && tuid < 10)//send成功後再修改賬戶餘額
	{
		accountMsg1[uid].balance = balance; //登入使用者賬號餘額
		accountMsg1[tuid].balance = accountMsg1[tuid].balance + rMsg.money; //被轉賬使用者賬號餘額
	}
	printf("___________transfer Money END__________\n\n");
	return 0;
}


int balanceEnquire(int iSocketClient,struct recvMsg rMsg,int uid)
{	
	printf("___________balance Enquire ing__________\n");
	int iSendLen;
	iSendLen = send(iSocketClient, &accountMsg1[uid].balance, sizeof(accountMsg1[uid].balance), 0);
	if (iSendLen <= 0)
	{
		printf("___________balance Enquire failed__________\n\n");
		close(iSocketClient);
		return -1;
	}
	printf("___________balance Enquire succeed__________\n\n");
	return 0;
}


//———————————————————————建立套接字——————————————————————————
int creatSocket()
{
	int iSocketServer;
	iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == iSocketServer)
	{
		printf("socket error!\n");
		return -1;
	}

	struct sockaddr_in tSocketServerAddr;//伺服器地址結構
	
	tSocketServerAddr.sin_family = AF_INET;
	tSocketServerAddr.sin_port   = htons(SERVER_PORT); 
 	tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
	memset(tSocketServerAddr.sin_zero, 0, 8);
	
	int iRet;
	iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
	if (-1 == iRet)
	{
		printf("bind error!\n");
		return -1;
	}
  
	iRet = listen(iSocketServer, BACKLOG);
	if (-1 == iRet)
	{
		printf("listen error!\n");
		return -1;
	}
	return iSocketServer;
}

//——————————————————————執行緒處理函式——————————————————————————
void *handle_client(void *arg)
{	
    int iSocketClient = *(int*)arg;
	int uid;
	printf("_____________________at handle thread____________________\n");
	while (1)
	{
		printf("____________________waiting client operation...____________________\n\n");
		struct recvMsg rMsg;
		memset(&rMsg,0,sizeof(rMsg));
		char buf[1024]={0};
		int iRecvLen = recv(iSocketClient, buf,1025, 0);
		memcpy(&rMsg,buf,sizeof(rMsg));	
		if (iRecvLen <= 0)
		{
			printf("_________________error recv_______________\n");
			break;
		}
		buf[iRecvLen] = '\0';
		//printf("_____3 rMsg.account:  %d  rMsg.password:  %d  rMsg.taskID: %d___\n",rMsg.account,rMsg.password,rMsg.taskID);	
		switch(rMsg.taskID)
		{
			case 0: uid = login(iSocketClient,rMsg);
					break;
			case 1: saveMoney(iSocketClient,rMsg,uid);
					break;
			case 2: withdrawMoney(iSocketClient,rMsg,uid);
					break;
			case 3: transferMoney(iSocketClient,rMsg,uid); 
					break;
			case 4: balanceEnquire(iSocketClient,rMsg,uid); 
					break;
			default:
					break;					
		 }
	 }
	//close(iSocketClient);
}


int main()
{
	memset(accountMsg1, 0, sizeof(accountMsg1)*10);
	accountMsg1[0].account = 123;
	accountMsg1[0].password = 456;
	accountMsg1[0].balance = 800;
	//accountMsg1[0].uCal = 1;//普通使用者
	accountMsg1[1].account = 1212;
	accountMsg1[1].password = 3456;
	accountMsg1[1].balance = 500;
	int iSocketServer;
	iSocketServer=creatSocket();
	if (-1 == iSocketServer)
	{
		printf("create socket failed!\n");
		return -1;
	}
	
	struct sockaddr_in iSocketClientAddr;//客戶端地址結構:當客戶端來連線時會傳過來
	int iAddrLen;
	int iRecvLen;
	printf("____server running,waiting for client conneting...__\n");
		
	while (1)
	{
		iAddrLen = sizeof(struct sockaddr);
		
		int iSocketClient = accept(iSocketServer, (struct sockaddr *)&iSocketClientAddr, &iAddrLen);
		if (-1 != iSocketClient)
		{
			printf("___accepted client message successed!__\n");
			pthread_t pid;
			pthread_create(&pid,NULL,handle_client,&iSocketClient);

			pthread_detach(pid);				
		}	
		//close(iSocketServer);
	}
	close(iSocketServer);
	return 0;
}


 

客戶端 client.c

#include <sys/types.h>        
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>


#define SERVER_PORT 8888

struct sendMsg
{
	//char *name;		//戶主姓名
	int account;		//賬號
	int password;		//密碼
	int money;		//金額
	int uCal;		//賬戶型別
	int taskID;		//操作任務型別
	
};


int verify(int iSocketClient,struct sendMsg sMsg) 	//驗證密碼
{
	printf("_________verify user info ing_______\n\n");
	int iSendLen;
	int iRecvLen;
	iSendLen = send(iSocketClient, (char *)&sMsg, sizeof(sMsg)+1, 0);
	//free(buf);
	if (iSendLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}
	//char accessBuf[20];
	int accessBuf=0;
	iRecvLen = recv(iSocketClient, &accessBuf, sizeof(accessBuf), 0);
	if (iRecvLen <= 0)
	{	
		close(iSocketClient);
		return -1;
	}
	if(0 == accessBuf)
	{
		return -1;
	}
	printf("_________verify user info succeed!_______\n\n");
	return 0;
}

void login(int iSocketClient)
{
	struct sendMsg sMsg;	
	loop0:printf("\n_____Welcome to bank client!_____\n\n");
	memset(&sMsg,0,sizeof(sMsg));
	loop1:printf("Please choose your identity:\n");
	printf("0 Manager		1 User\n");
	scanf("%d",&sMsg.uCal);
	if(1 != sMsg.uCal)
	{
		if(0 != sMsg.uCal)
		{
			printf("identity error! \n");
			goto loop1;
		}
	}		
	loop2:printf("account: ");
	scanf("%d",&sMsg.account);
	printf("password: ");
	scanf("%d",&sMsg.password);
	if(0 != verify(iSocketClient,sMsg))
	{
		printf("account or password error,please relogin! \n");
		goto loop2;
	}
	while(1)
	{
		printf("_____________Welcome to bank client!_____________\n");
		printf("_____________Main Business_____________\n\n");
		printf("1 saveMoney \n2 withdrawMoney \n3 transferMoney \n4 balanceEnquire \n5 exit\n");
		printf("\nPlease enter the business ID:");
		scanf("%d",&sMsg.taskID);
		printf("\n");
		switch(sMsg.taskID)
		{
			case 1: saveMoney(iSocketClient,sMsg);
					break;
			case 2: withdrawMoney(iSocketClient,sMsg);
					break;
			case 3: transferMoney(iSocketClient,sMsg); 
					break;
			case 4: balanceEnquire(iSocketClient,sMsg); 
					break;
			case 5: goto loop0;
					break;
			default:
					break;			
		}
	}
	
}

int balanceEnquire(int iSocketClient,struct sendMsg sMsg)
{	
	int iSendLen;
	int iRecvLen;
	printf("___________balance Enquire ing__________\n\n");	
	
	iSendLen = send(iSocketClient, &sMsg, sizeof(sMsg), 0);
	if (iSendLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}
	
	int balanceBuf;
	iRecvLen = recv(iSocketClient, &balanceBuf, sizeof(balanceBuf), 0);
	if (iRecvLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}
	else
	{
		printf("Your balance is:  %d\n\n",balanceBuf );
	}
	return 0;
}

int saveMoney(int iSocketClient,struct sendMsg sMsg)
{
	int iSendLen;
	int iRecvLen;
	printf("___________save Money ing__________\n\n");	
	printf("please enter the money: ");
	scanf("%d",&sMsg.money);
	
	iSendLen = send(iSocketClient, &sMsg, sizeof(sMsg), 0);
	if (iSendLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}
	
	int balanceBuf;
	iRecvLen = recv(iSocketClient, &balanceBuf, sizeof(balanceBuf), 0);
	if (iRecvLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}
	else
	{
		printf("Save Succeed!\n Your balance is:  %d\n\n",balanceBuf );
	}
	return 0;
}

int withdrawMoney(int iSocketClient,struct sendMsg sMsg)
{
	int iSendLen;
	int iRecvLen;
	printf("___________withdraw Money ing__________\n\n");	
	printf("please enter the money: ");
	scanf("%d",&sMsg.money);
	
	iSendLen = send(iSocketClient, &sMsg, sizeof(sMsg), 0);
	if (iSendLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}
	
	int balanceBuf;
	iRecvLen = recv(iSocketClient, &balanceBuf, sizeof(balanceBuf), 0);
	if (iRecvLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}
	else if(balanceBuf < 0)
	{
		printf("withdraw failed!\n Your balance is not sufficient!\n\n" );
	}
	else
	{
		printf("withdraw Succeed!\n Your balance is:  %d\n\n",balanceBuf );
	}
	return 0;

}

int transferMoney(int iSocketClient,struct sendMsg sMsg)
{
	printf("___________transfer Money ing__________\n\n");
	int iSendLen;
	int iRecvLen;
	
	printf("please enter payee's account: ");
	scanf("%d",&sMsg.account);
	printf("please enter the money: ");
	scanf("%d",&sMsg.money);
	
	iSendLen = send(iSocketClient, &sMsg, sizeof(sMsg), 0);
	if (iSendLen <= 0)
	{
		close(iSocketClient);
		return -1;
	}

	int balanceBuf;
	iRecvLen = recv(iSocketClient, &balanceBuf, sizeof(balanceBuf), 0);
	if (iRecvLen <= 0)
	{
		printf("___________transfer Money failed__________\n\n");
		close(iSocketClient);
		return -1;
	}
	else if(balanceBuf < 0)
	{
		printf("transfer failed!\n The account is wrong or your balance is not sufficient! \n\n" );
	}
	else
	{
		printf("transfer Succeed!\n Your balance is:  %d\n\n",balanceBuf );
	}
	
	return 0;
}


int CreatSocekt()
{
	int iSocketClient;
	iSocketClient = socket(AF_INET, SOCK_STREAM, 0);
	
	struct sockaddr_in tSocketServerAddr;	
	
	tSocketServerAddr.sin_family = AF_INET;
	tSocketServerAddr.sin_port   = htons(SERVER_PORT);
	tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);   
 	if (0 == inet_aton("10.1.65.142", &tSocketServerAddr.sin_addr))
 	{
		printf("Server IP error!\n");
		return -1;
	}
	memset(tSocketServerAddr.sin_zero, 0, 8);
	
	int iRet;
	iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	
	if (-1 == iRet)
	{
		printf("connect failed!!\n");
		return -1;
	}
	
	return iSocketClient;
}



int main()
{	
	int iSocketClient = CreatSocekt();
	if (-1 == iSocketClient)
	{
		printf("socket error!\n");
		return -1;
	}
	
		
	login(iSocketClient);
		
		
	close(iSocketClient);
	return 0;
}


注:linux系統中,因為使用了多執行緒函式,所以編譯時加上 -lpthread

gcc server.c -o server -lpthread

gcc client.c -o client -lpthread