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.

 

  1. Description of system modules

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.

  1. The status of each process:
  2.  

     

     

     

     

    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.

     

  3. The protocol of communication between entities:

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.

    1. /* Send a start signal to a gambler, tell him to the game will start.*/
    2. Format: STAT

      Return : 100 error

      200 ok

    3. /* dealer give gambler a card. */
    4. Format: CARD [int]

      Return : 100 error

      200 ok

      201 standing

    5. /* dealer give gambler his information. */
    6. Format: DCAD [int]

      Return : 100 error

      200 ok

    7. /* dealer tell gambler that he has win. */
    8. Format: WIN_ [int]

      Return : 100 error

      200 ok

    9. /* dealer tell gambler that he has lost. */
    10. Format: LOST [int]

      Return : 100 error

      200 ok

    11. /* dealer tell gambler that the gambling is tied. */
    12. Format: TIED [int]

      Return : 100 error

      200 ok

    13. /* Send a end signal to a gambler, tell him to the game has end.*/

Format: END_

Return : 100 error

200 ok

    1. /* gambler tell dealer how much he will gamble.*/

Format: CHIP [int]

Return : 100 error

200 ok

    1. /* dealer register himself in the bank.*/

Format: REGI name ip port

Return : 100 error

200+id return dealer id (account number).

    1. /* dealer tell bank he will quit from this bank.*/
    2. Format: QUIT id

      Return : 100 error

      200 ok

    3. /* dealer get or return chips to bank. Negative means return chips*/
    4. Format: CHIP [int]

      Return : 100 error

      200 ok

    5. /* dealer tell bank in this hand he has won*/
    6. Format: WIN_ [int]

      Return : 100 error

      200 ok

    7. /* dealer tell bank in this hand he has lost*/

Format: LOST [int]

Return : 100 error

200 ok

Format: CHIP [int]

Return: 100 error

    1. ok

Format RETU [int]

Return: 100 error

    1. ok

Format: WIN_ [int]

Return: 100 error

    1. ok

Format: LOST [int]

Return: 100 error

    1. Ok
  1. The implementation of process dealer

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.

      1. Give every player and dealer himself two cards.
      2. Send the dealer’s second card information to all players.
      3. Players may use this information to make their own decision to get cards or standing.

      4. Give every player's cards until he says STANDING.
      5. Give dealer cards until his point is greater than 17.
      6. Check every player to see who is win or lost.
      7. Send every player a notification to tell them win or lost.

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();

}

 

  1. The implementation of process gambler

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*/

  1. int playgame(int sockfd, int *result, int totalchips, int eachchips, int *insufficient)
  2. 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

  3. int search_dealer(int *sockfd, int *flags, int number)
  4. 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

  5. int connectbank(int sockfd, char *bankaddr, int chip, int mission)

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

  1. The implementation of process bank

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

 

  1. The running result of project

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

 

  1. Members’ role in the development of project

Ruofei Zhang

  • Software protocol design;
  • Design and implementation of process Bank and Gambler;
  • Documents writing;
  • Program Testing and debugging

Donghui Wen

  • Software protocol design;
  • Design and implementation of process Dealer;
  • Documents writing;
  • Program Testing and debugging

Hui Zhang

  • Studying rules of Backjack;
  • Documents writing

 

  1. Future work
  2. (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.

     

  3. Attachment--------Source code