CS528 Final Project Report
Ruofei Zhang, Donghui Wen, Hui Zhang
This is a course project of CS528 (Computer Network). It simulates the activities of a gambling casino containing multiple blackjack tables. There are three modules in this design: dealer, gambler and bank. Several gamblers can connect to one dealer to play blackjack game. All dealers and gamblers can exchange chips from a bank.
We divided the system into three software programs, which plays the role of bank, dealer and gambler respectively. Each program is running on an independent computer host and they communicate with each other by exchange message using TCP socket stream. First, we describe the main functions and activities of each program:

Communicating with bank process. In this communication, gambler is a client and bank is a server. By the communication gambler exchanges certain amount of chips. Then Reading the dealer list file, which contains all possible dealers’ IP address. Then gambler tries to connect the possible dealers in the list. After connecting to an available dealer successfully, the gambler will begin to wait for the game start message packet from selected dealer. Otherwise if all dealers in the dealer list are not available, the gambler will sleep one second and then retry all possible dealers once again, utill he connects to one dealer successfully. When the dealer process discover that there has been enough gamblers (Six) requested in or the time of waiting for gamblers (5 Seconds) time out, the dealer will send a message packet to all gamblers participating in coming game to notify them the game will begin. Then gambler must submit the bet chips to the dealer and receive two cards (message packets) sent by dealer consecutively. Afterward, the first card of dealer will be sent from dealer so the gambler can know dealer’s first card too. Then the gambler decides whether he/she will accept more cards or refuse to accept any more cards. The decision algorithm is very simple, if total points the gambler got is equal to or greater than 18, the gambler will standing, does not accept another card, otherwise, he/she will accept next card. After the result of game comes, the dealer will send a message to each gambler to inform them whether he/she is winning or losing. Then the game is finished. After the game ends, gambler will connect to bank to exchange chips once again. And the gambler must decide whether he/she will continue to play or to leave. In the implementation of gambler process, if gambler has played 10 hands, he/she will exit. Otherwise he/she will search possible dealers once again to get one available dealer, then replay another game. If he/she will exit, then before he/she exits, he/she will connect bank to report how many chips he win/lost totally. He all will return all left chips he/she has to bank.
When the dealer process is running initially, before the dealer open a game it will connect to banker to exchange some chips. In this communication, gambler is a client and banker is a server. After close the connection with banker, the dealer acts as a server, which accepts the connection request from some gamblers. When the number of logged gamblers comes to six or the waiting time (5 seconds) time out, the dealer will stop accepting new gamblers and begin to play game with current gamblers in this hand. At this time, dealer is a concurrency server, which receive messages from and send messages to gambler process. First, it will notify all gamblers the game is beginning and receive bet chips report from each gambler. If he decide that the chips it has are not enough, it will connect to bank to exchange amount of chips. During the game playing, the dealer produces cards randomly. First it will send two cards to each gambler, then it will send its card information (one card) to each gambler too. It will also communicate with each gambler to get if he/she will accept another card and record each gambler’s score. It’s the dealer that decides when the game is finished and notifies each gambler that whether he/she wins or loses and how many chips he/she wins/loses. After the game ends, the dealer will connect to banker once again to report the winning or losing of chips and maybe exchange some chips too. Then the dealer closes the connection with bank and again acts as a concurrency server waiting for the gambler to log in.
Process Bank provides two services, one for gambler, the other for dealer. It’s one process but it listens on two ports (one for dealers, the other for gamblers). In the service for gambler, it will exchange chips with gamblers and it will report the results from gamblers. In the service for dealers, it will also exchange chips with dealers and it will receive the report from dealers after each game and calculates the result. In addition, bank process save all records of game activities (exchange chips from gamblers or dealers, report from dealers about game result, report from gamblers about their final win/lose result). In addition, bank also receives keyboard command to display all log records. The total chips in bank are a global variant for both program communicating to dealers and program communicating to gamblers.
|
Pure Client |
Gambler program (communicating with bank and dealer) |
|
Pure Iterative Server |
Banker program (acts as two servers, one for dealers, the other for gamblers. |
|
Client/Concurrency Server |
Dealer program (acts as a concurrency server for gambler and a client to banker) |
Each communication between client and server is a TCP stream communication. We create Stream sockets on each end of the communications.
Before we began to write code, the first thing we have to do is to define the protocols amongst three processes. We decide to use string as the format of protocol. Just like File Transfer Protocol (FTP). In this way, each part of the project would not share a common data structure; they even can be implemented in different programming languages. In fact, in this implementation, Dealer is written using C++, while Gambler and Bank are written using C.
Format: STAT
Return : 100 error
200 ok
Format: CARD [int]
Return : 100 error
200 ok
201 standing
Format: DCAD [int]
Return : 100 error
200 ok
Format: WIN_ [int]
Return : 100 error
200 ok
Format: LOST [int]
Return : 100 error
200 ok
Format: TIED [int]
Return : 100 error
200 ok
Format: END_
Return : 100 error
200 ok
Format: CHIP [int]
Return : 100 error
200 ok
Format: REGI name ip port
Return : 100 error
200+id return dealer id (account number).
Format: QUIT id
Return : 100 error
200 ok
Format: CHIP [int]
Return : 100 error
200 ok
Format: WIN_ [int]
Return : 100 error
200 ok
Format: LOST [int]
Return : 100 error
200 ok
Format: CHIP [int]
Return: 100 error
Format RETU [int]
Return: 100 error
Format: WIN_ [int]
Return: 100 error
Format: LOST [int]
Return: 100 error
We wrote dealer using C++(GCC2.8.1) in bingsuns. In this blackjack program, we don’t use mutiprocesses or multithreads. At a specific time, a dealer will only communicate with one gambler. All gamblers connected to one dealer will send or receive message from dealer in turn. It isn’t a concurrent problem. When a dealer is playing game, it will close its listening socket. All other gamblers wanted to connect will fail. It will cause the gambler to find another idle dealer to join. I will describe beliefly about the class structure and functions of the dealer program in the following section:
class TcpSocket
{
public:
/* create a socket. */
int socket();
/* send and receive string. */
int send(int sock, string message);
string receive(int sock);
/* convert a string ip to network address. */
int inet_aton(const char *cp, struct in_addr *ap);
/* convert a network address to an ip string. */
int inet_ntoa(char *cp, struct in_addr *ap);
};
class TcpClient : public TcpSocket
{
public:
/* the connection socket. */
int sock;
TcpClient(string remoteip, int port);
~TcpClient();
/* connect to a Tcp server. */
int connect(struct sockaddr *name, int namelen);
/* send a string . */
int send(string message);
/* receive a string */
string receive();
/* close the connection. */
void close();
};
class TcpServer : public TcpSocket
{
public:
/* the listening socket. */
int listensock;
/* local host address. */
struct sockaddr_in localaddr;
/*local listening port. */
int localport;
/* local ip string and hostname */
string localip;
string hostname;
TcpServer(int port);
~TcpServer();
/* initialize the server. */
int init();
/* bind to a socket address. */
int bind(sockaddr *addr, size_t length);
/* listen network connections. */
int listen(int n);
/* accept a connection. */
int accept(sockaddr *addr, int *length_ptr);
};
class Dealer : public TcpServer
{
public:
/* The name of this dealer.*/
string name;
/* The ip address of bank. */
string bankIP;
/* Gambler list. */
vector<Gambler> gamblerList;
/* card list .*/
vector<Card> cards;
/* dealer's card list */
vector<Card> myCards;
/* dealer's current points. */
int points;
/* dealer's current chips. */
int chips;
/* dealer's previous chips. */
int oldChips;
/*if it is timeout when waiting for gamblers. */
static bool isTimeout;
/* if this is the first gambler. */
bool isFirstGambler;
/* if the game has started. */
bool isGameHasStarted;
/* The next card id. */
int nextCardId;
Dealer(string name,int port);
~Dealer();
/* signal call back function. */
static void timeout(int signo);
/* initialize the card sequence randomly. */
void initCards();
/* get next card. */
Card getNextCard();
string toString(int d);
/* add a card to dealer. */
bool addMyCard();
/* waiting for gamblers. */
bool waitForPlayers();
/* accept a player. */
int acceptPlayer();
void setBankIP(string ip);
void registration(string bankAddr);
void unregistration();
/* communicate with bank process. */
int talkwithbank(string message);
/* get chips from bank. */
void askForChips(int amount);
/* shudown the dealer server. */
void shutdown();
/* close the dealer server. */
void close();
/* send a message to player and get an acknoledgement. */
int send_recv(int playerId,string message);
/* report WIN or LOST */
void report();
void playGame(); /* play game. */
void gameStart(); /* start game. */
void gameOver(); /* end game. */
};
Functions:
initCards initialize the card sequence in a random manner. It use the current system time and process id as seed to generate random number.
This function waits for players to join until timeout or six players has come. When the first player arrives, it will set up a timer. Each player’s info (including its socket) will be put into a player list that is dynamic array. After timeout or having six players, it will close the listening socket.
This Function will accept a player, remember its socket.
This Function send a string to a player and receive a acknowledge string from the player.
It tells every player to start to play game. After sending the START signal, it will wait to collect every player’s gamble. And if necessary, the dealer will contact bank to buy more chips in order to have enough money to play game.
This is the function which do most of the work.
Players may use this information to make their own decision to get cards or standing.
Tell each player to end game.
Report each hands with players.
This is the main function.
void main(char** argv, int argc)
{
Dealer dealer("The king",5678);
if (argc > 2 )
{
cout << "Usage : dealer [128.226.6.4] \n";
exit(0);
}
else if (argc == 2)
dealer.setBankIP(argv[1]);
cout << dealer.localip << '\t' << dealer.hostname << endl;
dealer.askForChips(200);
while (dealer.waitForPlayers())
{
dealer.gameStart();
dealer.playGame();
dealer.gameOver();
dealer.report();
}
dealer.close();
}
In the implementation of process gambler, we employ nonblocking socket and I/O multiplexing (Select function) to implement the communication to bank and dealer.
The input arguments for gambler program is:
player <Bank's Host Name> <first chips> <each chips> <after chips> <total rounds>
|
Bank’s Host Name |
The name of host on which the Bank is running |
|
First chips |
The number of chips that gambler will exchange with bank initially |
|
Each chips |
The number of chips that gambler will bet in each game |
|
After chips |
The number of chips that gambler may exchange with bank after each game ends |
|
Total rounds |
The total number of rounds that gambler want to play |

#define DEALER_PORT 5678 /*define dealer's listen port*/
#define BANK_PORT 6001 /*define bank's listen port*/
The function implements one game playing with a dealer.
Arguments: int sockfd Socket ID connecting with one dealer
int *result The pointer points to the result of this game
(*result>=0 The number of chips gambler win)
(*result<0 The number of chips gambler lost)
int totalchips The total chips of this gambler before he play the game
int eachchips The number of chips gambler used in each game
int *insufficinet The pointer points to the flag of not enough chips (*insufficient>0 Not sufficient chips to play)
(*insufficient==0 sufficient chips to play)
return value: int =0 The game finished normally
!=0 The game finished with exception
The function implements to search dealer list to find an available dealer for one gambler.
Arguments: int *sockfd The pointer points to the socket ID used to search available dealer
int *flags The pointer points to the flag used to set socket with NON_BLOCK option
int number The number of totally possible dealers
return value: int =1 The gambler find one available dealer
=0 No availabe dealer is found
The function implements to connect bank to exchange, return or report win, lost result for one gambler.
Arguments: int sockfd The socket ID used to connect bank
char *bankaddr Bank's host name
int chip The number of chips which gambler will operate to bank
int mission The mission ID of different connection tasks
1: exchange(chip>=0) or return (chip<0) chips to bank
2: report win chips to bank
3: report lost chips to bank
return value: int =1 The communication with bank is successful
=0 The communication with bank is not successful
In the implementation of process bank, we employ I/O multiplexing (Select function) to implement the two servers (one for gamblers and the other for dealers) as well as accepting command from keyboard to print out log records.

#define MAXLINE 100 buffer length
#define LISTENQ 5 listening queue length
#define BANK_PORT1 6001 bank port to gamblers
#define BANK_PORT2 6002 bank port to dealers
#define MAX_CHIPS 100000 the initial chips bank has
typedef struct record {
int chips; number of chips
char people[50]; people(gambler or dealer) and their operation on chips
}
bankrecord; Log record data type
The software we developed works well. We have tested several test cases many times, which includes:
The output of bank for one running: (bank is running on binguns, two dealers are running on ultra3 and ultra5, respectively. Two gamblers are running on ultra2 and ultra6 respectively. Gambler(ultr6) played 2 rounds and gambler(ultra2) played 3 rounds).
Log number People Record(chips)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 ||dealer 128.226.4.23 exchange. ||200
1 ||dealer 128.226.4.25 exchange. ||200
2 ||gambler 128.226.4.26 exchange ||100
3 ||gambler 128.226.4.22 exchange ||100
4 ||dealer 128.226.4.23 exchange. ||100
5 ||gambler 128.226.4.26 exchange ||10
6 ||gambler 128.226.4.22 exchange ||10
7 ||dealer 128.226.4.23 win. ||20
8 ||dealer 128.226.4.23 exchange. ||100
9 ||gambler 128.226.4.26 exchange ||10
10 ||gambler 128.226.4.22 exchange ||10
11 ||gambler 128.226.4.26 return ||100
12 ||gambler 128.226.4.26 lost. ||20
13 ||dealer 128.226.4.23 exchange. ||100
14 ||dealer 128.226.4.23 win. ||10
15 ||gambler 128.226.4.22 exchange ||10
16 ||gambler 128.226.4.22 return ||120
17 ||gambler 128.226.4.22 lost. ||10
GamblerResult Chips
gambler 128.226.4.26 lost ||20
gambler 128.226.4.22 lost ||10
Gamblers checked in: 2
Gamblers checked ou: 2
Chips checked in: 100000
Chips checked out: 100000
Initially we have 100000 dollars.
Now we have total 100030 chips
|
Ruofei Zhang |
|
|
Donghui Wen |
|
|
Hui Zhang |
|
(1) Robustness. Our implementation is not robust enough. There are many exceptions in the communication. We just make our program exit simply.
(2) Portability. We have just tested our programs in Sun’s Solaris system. And we could not compile successfully in Windows.
(3) GUI. Our implementation has no graphic user interface. It is NOT a real game.