用socket c++编程的战舰游戏ubuntu

C++ Programming with socket Battleship game ubuntu

本文关键字:游戏 ubuntu socket c++ 编程      更新时间:2023-10-16

我有以下c++程序,使用套接字编程的战舰游戏,它是写在窗口。但我需要它在ubuntu上运行。请协助提出建议。我如何继续实现代码,我知道ubuntu,套接字编程部分将不同于窗口。

编码:服务器

            //Battleship Server
            #include <iostream>     //For basic I/O operations
            #include <conio.h>      //For _getch(); to pause the program
            #include <winsock2.h>   //For network operations
            #include <windows.h>    //Needed by winsock
            #include <ws2tcpip.h>   //Used for and addrinfo related functions
            #include <time.h>       //For rand()
            #define BUFLEN 64       //Default buffer length
            #define PORT "3490"     //Port to be used 
            #pragma warning(push)
            #pragma warning(disable:4996)
            using namespace std;
            //Global ship names and corresponding letters
            char *Shipnames[5] = {
                "Aircraft Carrier",
                "BattleShip",
                "Destroyer",
                "Submarine",
                "patrol Boat",
            };
            char Letter[5] = { 'A', 'B', 'D', 'S', 'P' };
            struct Ship
            {
                //To keep track of hits
                char Hitbox[5];
                //X & Y positions
                int X;
                int Y;
                //Length of ship
                int len;
                //Direction
                //true = vertical (Y)
                //false = horizontal (X)
                bool Direction;
            };
            //Translates letter cords to numbers
            //eg: A5 = 15, B7 = 27, E3 = 53
            int TransLettoNumb(char *Cord)
            {
                char Letters[8] = {
                    'A',
                    'B',
                    'C',
                    'D',
                    'E',
                    'F',
                    'G',
                    'H',
                };
                char Lowercase[8] = {
                    'a',
                    'b',
                    'c',
                    'd',
                    'e',
                    'f',
                    'g',
                    'h',
                };
                //Check through upper case
                for (int x = 0; x < 8; x++)
                {
                    if (Cord[0] == Letters[x])
                        return x + 1;
                }
                //check through lower case
                for (int x = 0; x < 8; x++)
                {
                    if (Cord[0] == Lowercase[x])
                        return x + 1;
                }
                return 0;
            }
            bool sendl(int sockfd, bool hit)
            {
                char *Line = new char[BUFLEN];
                if (hit)
                {
                    Line = "Hit!";
                }
                else
                {
                    Line = "Miss!";
                    cout << "Miss!" << endl;
                }
                bool var = true;
                if (send(sockfd, Line, strlen(Line), 0) == SOCKET_ERROR)
                    var = false;
                return var;
            }
            //For checking if the client hit a boat
            bool Checkhit(Ship ships[], char Cord[], int sockfd)
            {
                //Translate cords to ints
                int Ycord = (Cord[1] - 48);
                int Xcord = TransLettoNumb(Cord);
                //Length of ship
                int Len;
                //For each ship
                for (int n = 0; n < 4; n++)
                {
                    //Set length
                    if (n == 0)
                        Len = 5;
                    else if (n == 1)
                        Len = 4;
                    else if (n == 2)
                        Len = 3;
                    else if (n == 3)
                        Len = 3;
                    else if (n == 4)
                        Len = 2;
                        //loop through the hitbox
                        for (int i = 0; i < Len; i++)
                        {
                            //If the x cord equals the ships cords plus hitbox (i), test y cords
                            if (Xcord == (ships[n].X + i))
                            {
                                //loop through the hitbox
                                for (int i = 0; i < Len; i++)
                                {
                                    //If the y cord equals the ships cords plus hitbox (i)
                                    if (Ycord == (ships[n].X + i))
                                    {
                                        //the ship was hit, update the hitbox
                                        ships[n].Hitbox[i] = 'X';
                                        {                           
                                            cout << Shipnames[n] << " was hit!"<< endl;
                                            //send hit
                                            sendl(sockfd, true);
                                            //Send which ship was hit
                                            send(sockfd, Shipnames[n], strlen(Shipnames[n]), 0);
                                            return true;
                                        }
                    }
                    }
                    }
                    }
                    }
                //The ship was not hit
                return false;
            }
            void PlaceShips(Ship ships[])
            {
                int randnumb;
                //For each ship
                for (int n = 0; n < 5; n++)
                {
                    //Randomize direction
                    randnumb = rand() % 2;
                    if (randnumb == 1)
                        ships[n].Direction = true;
                    else
                        ships[n].Direction = false;
                    do
                    {
                        randnumb = 0;
                        //randomize x
                        ships[n].X = rand() % 8 + 1;
                        //randomize y
                        ships[n].Y = rand() % 8 + 1;
                        //If direction is true, check y 
                        if (ships[n].Direction)
                        {
                            //If the ship hit the wall
                            if ((ships[n].Y + ships[n].len) > 8)
                                randnumb = 1;
                        }
                        else //else check x
                        {
                            //If the ship hit the wall
                            if ((ships[n].X + ships[n].len) > 8)
                                randnumb = 1;
                        }
                    } while (randnumb > 0);
                }
            }
            int main()
            {
                //Quit flag
                bool quit = false;
                //Initialize random seed
                srand(time(NULL));
                //Declare ships
                Ship ships[5];
                //Initialize ship lengths
                ships[1].len = 5;
                ships[2].len = 4;
                ships[3].len = 3;
                ships[4].len = 3;
                ships[5].len = 2;
                //Hit counter
                int HitCounter = 0;
                //Declare some winsock variables
                int status;                                 //To keep track of errors
                WSADATA wsaData;                            //For winsock initialization
                SOCKET ListenSocket = INVALID_SOCKET;       //Socket for listening on
                SOCKET ClientSocket = INVALID_SOCKET;       //Socket for communicating with client
                struct addrinfo *result = NULL;             //struct to hold address information
                struct addrinfo address;                    //struct to hold connection information
                char recvbuf[BUFLEN];                       //Buffer for receiving information
                char sendbuf[BUFLEN];                       //Buffer for sending
                // Initialize Winsock
                status = WSAStartup(MAKEWORD(2, 2), &wsaData);
                if (status != 0) 
                {
                    cout << "failed to initialize winsock" << endl;
                    _getch();
                    return 1;
                }
                ZeroMemory(&address, sizeof(address));
                address.ai_family = AF_INET;
                address.ai_socktype = SOCK_STREAM;
                address.ai_protocol = IPPROTO_TCP;
                address.ai_flags = AI_PASSIVE;
                //Get IP and port info
                status = getaddrinfo(NULL, PORT, &address, &result);
                if (status != 0)
                {
                    cout << "getaddrinfo failed with error: " << WSAGetLastError() << endl;
                    freeaddrinfo(result);
                    _getch();
                    return 1;
                }
                //Create a socket for listening
                ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
                if (ListenSocket == INVALID_SOCKET)
                {
                    cout << "failed to create socket with error: " << WSAGetLastError() << endl;
                    freeaddrinfo(result);
                    _getch();
                    return 1;
                }
                //Bind to the port
                status = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
                if (status == SOCKET_ERROR)
                {
                    cout << "failed with error " << WSAGetLastError() << " binding to port " << PORT << endl;
                    freeaddrinfo(result);
                    _getch();
                    return 1;
                }
                else cout << "binded to port " << PORT << endl;
                //Done with the results
                freeaddrinfo(result);
                //Server loop
                while (quit == false)
                {
                    //Listening for client connections
                    //5 is the amount of clients that can wait on queue
                    status = listen(ListenSocket, 5);
                    if (status == SOCKET_ERROR)
                    {
                        cout << "listen() failed with error: " << WSAGetLastError() << endl;
                        closesocket(ListenSocket);
                        WSACleanup();
                        _getch();
                        return 0;
                    }
                    //Accept client connection
                    ClientSocket = accept(ListenSocket, NULL, NULL);
                    if (ClientSocket == INVALID_SOCKET)
                    {
                        cout << "accept failed with error: " << WSAGetLastError() << endl;
                        closesocket(ClientSocket);
                        WSACleanup();
                        _getch();
                        return 1;
                    }
                    else cout << "connection accepted from client" << endl;
                    //set up game...
                    int cord;
                    //Initialize ship hitboxes
                    for (int x = 0; x <5; x++)
                    {
                        //Initialize hitbox
                        for (int i = 0; i<5; i++)
                            ships[x].Hitbox[i] = Letter[x];
                    }

                    //Randomize ship locations
                    PlaceShips(ships);
                    status = 1;
                    //Game loop
                    while (status > 0)
                    {
                        ///Receive client's bomb cords
                        status = recv(ClientSocket, recvbuf, BUFLEN, 0);
                        cout << endl << "client bombed square " << recvbuf[0] << recvbuf[1] << endl;
                        //Check if it was a hit or miss and reply to client
                        if (!Checkhit(ships, recvbuf, ClientSocket))
                            sendl(ClientSocket, false);
                        else
                            HitCounter++;
                        status = 0;
                        //generate random cord
                        do
                        {
                            cord = rand() % 8;
                            if (cord >= 0 && cord < 9)
                                sendbuf[0] = (cord + 65);
                            else
                                status = 1;
                            cord = rand() % 8;
                            if (cord >= 0 && cord < 9)
                                sendbuf[1] = (cord + 49);
                            else
                                status = 1;
                        } while (status == 1);
                        //send cord guess
                        send(ClientSocket, sendbuf, BUFLEN, 0);
                        cout << endl << "guessing " << sendbuf[0] << sendbuf[1] << endl;
                        //recv hit or miss
                        status = recv(ClientSocket, recvbuf, BUFLEN, 0);
                        //Display hit/miss
                        for (int x = 0; x < status; x++)
                        {
                            cout << recvbuf[x];
                        }
                        cout << endl;
                        //If all the boxes have been hit
                        if (HitCounter == 17)
                        {
                            //send game complete
                            strcpy(sendbuf, "game complete!");
                            cout << sendbuf << endl;
                            send(ClientSocket, sendbuf, BUFLEN, 0);
                        }   
                    }
                    cout << "client disconnected" << endl;
                }
                _getch();
                return 0;
            }

编码:客户端

            //Battleship Client
            #include <iostream>     //For basic I/O operations
            #include <conio.h>      //For _getch(); to pause the program
            #include <winsock2.h>   //For network operations
            #include <windows.h>    //Needed by winsock
            #include <ws2tcpip.h>   //Used for and addrinfo related functions
            #include <string>       //For string functions
            #include <time.h>       //For rand() functions  
            #define BUFLEN 64       //Default buffer length
            #define PORT "3490"     //Port to be used
            using namespace std;
            //Global ship names and corresponding letters
            string Shipnames[5] = {
                "Aircraft Carrier",
                "BattleShip",
                "Destroyer",
                "Submarine",
                "patrol Boat",
            };
            char Letter[5] = { 'A', 'B', 'D', 'S', 'P' };
            struct Ship
            {
                //To keep track of hits
                char Hitbox[5];
                //the length of the ship
                int len;
                //X & Y positions
                int X;
                int Y;
                //Direction
                //true = vertical (Y)
                //false = horizontal (X)
                bool Direction;
            };
            bool SendLine(int sockfd, string desc)
            {
                char *Text = new char[BUFLEN];
                cout << desc << endl;
                cin.getline(Text, BUFLEN, 'n');
                if (strcmp(Text, "V") == 0 || strcmp(Text, "v") == 0)
                {
                    delete[] Text;
                    return true;
                }
                if (send(sockfd, Text, BUFLEN, 0) == SOCKET_ERROR)
                    cout << "server down" << endl;
                delete[] Text;
                return false;
            }
            //Translates letter cords to numbers
            //eg: A5 = 15, B7 = 27, E3 = 53
            int TransLettoNumb(char *Cord)
            {
                char Letters[8] = {
                    'A',
                    'B',
                    'C',
                    'D',
                    'E',
                    'F',
                    'G',
                    'H',
                };
                char Lowercase[8] = {
                    'a',
                    'b',
                    'c',
                    'd',
                    'e',
                    'f',
                    'g',
                    'h',
                };
                //Check through upper case
                for (int x = 0; x < 8; x++)
                {
                    if (Cord[0] == Letters[x])
                        return x+1;
                }
                //check through lower case
                for (int x = 0; x < 8; x++)
                {
                    if (Cord[0] == Lowercase[x])
                        return x+1;
                }
                return 0;
            }
            void UpdateShipGrid(char Grid[8][8], Ship ships[])
            {

            }
            //For checking if the server hit a boat
            bool Checkhit(Ship ships[], char Cord[], char ShipGrid[8][8])
            {
                //Translate cords to ints
                int Xcord = TransLettoNumb(Cord);
                int Ycord = (Cord[1] - 48); //we -48 to convert from ascii value
                //Length of ship
                int Len;
                //For each ship
                for (int n = 0; n < 4; n++)
                {
                    //Set length
                    if (n == 0)
                        Len = 5;
                    else if (n == 1)
                        Len = 4;
                    else if (n == 2)
                        Len = 3;
                    else if (n == 3)
                        Len = 3;
                    else if (n == 4)
                        Len = 2;
                    //loop through the hitbox
                    for (int i = 0; i < Len; i++)
                    {
                        //If the x cord equals the ships cords plus hitbox (i), test y cords
                        if (Xcord == (ships[n].X + i))
                        {
                            //loop through the hitbox
                            for (int i = 0; i < Len; i++)
                            {
                                //If the y cord equals the ships cords plus hitbox (i)
                                if (Ycord == (ships[n].X + i))
                                {
                                    //the ship was hit, update the hitbox and grid
                                    ships[n].Hitbox[i] = 'X';
                                    UpdateShipGrid(ShipGrid, ships);
                                    return true;
                                }
                            }
                        }
                    }
                }
                //The ship was not hit
                return false;
            }
            bool sendl(int sockfd, bool hit)
            {
                char *Line = new char[BUFLEN];
                if (hit)
                {
                    Line = "Hit!";
                    cout << "Hit!" << endl;
                }
                else
                {
                    Line = "Miss!";
                    cout << "Miss!" << endl;
                }
                bool var = true;
                if (send(sockfd, Line, strlen(Line), 0) == SOCKET_ERROR)
                    var = false;
                return var;
            }
            void DisplayGrid(char GridA[8][8], char GridB[8][8]) 
            {
                cout << "     Hit Grid          Ship Grid   " << endl;
                cout << "  A B C D E F G H   A B C D E F G H" << endl;
                for (int n = 1; n < 9; n++)
                {
                    cout << n << " ";
                    for (int i = 0; i < 8; i++)
                    {
                        cout << GridA[n][i] << " ";
                    }
                    cout << "| ";
                    for (int t = 0; t < 8; t++)
                    {
                        cout << GridB[n][t] << " ";
                    }
                    cout << endl;
                }
            }
            void InitGrid(char grid[8][8], Ship ships[])
            {
                //For the first dimension (x)
                for (int n = 0; n < 9; n++)
                {
                    //For the second dimension (y)
                    for (int i = 0; i < 9; i++)
                    {
                        //Give the box an empty space
                        grid[i][n] = ' ';
                    }
                }
            }
            void PlaceShips(Ship ships[], char Grid[8][8])
            {
                int randnumb;
                //For each ship
                for (int n = 0; n < 5; n++)
                {
                    //Randomize direction
                    randnumb = rand() % 2;
                    if (randnumb == 1)
                        ships[n].Direction = true;
                    else
                        ships[n].Direction = false;
                    do
                    {
                        randnumb = 0;
                        //randomize x
                        ships[n].X = rand() % 8 + 1;
                        //randomize y
                        ships[n].Y = rand() % 8 + 1;
                        //If direction is true, check y 
                        if (ships[n].Direction)
                        {
                            //If the ship hit the wall
                            if ((ships[n].Y + ships[n].len) > 8)
                                randnumb = 1;
                            else
                            {
                                //Place each hitbox on grid
                                for (int i = 0; i < ships[n].len; i++)
                                    Grid[ships[n].X][(ships[n].Y + i)] = ships[n].Hitbox[i];
                            }
                        }
                        else //else check x
                        {
                            //If the ship hit the wall
                            if ((ships[n].X + ships[n].len) > 8)
                                randnumb = 1;
                            else
                            {
                                //Place each hitbox on grid
                                for (int i = 0; i < ships[n].len; i++)
                                    Grid[(ships[n].X + i)][ships[n].Y] = ships[n].Hitbox[i];
                            }
                        }           
                    } while (randnumb > 0);
                }
            }
            int main(int argc, char **argv)
            {
                // Validate the parameters
                if (argc != 2) 
                {
                    cout << "Syntax: <server-ip>" << endl;
                    _getch();
                    return 1;
                }
                //Quit flag
                bool quit = false;
                //Keep track of hits
                int HitCounter = 0;
                //Initialize random seed
                srand(time(NULL));
                //Declare ships
                Ship ships[5];
                //Initialize ship lengths
                ships[0].len = 5;
                ships[1].len = 4;
                ships[2].len = 3;
                ships[3].len = 3;
                ships[4].len = 2;
                //Declare some winsock variables
                int status;                                 //To keep track of errors
                WSADATA wsaData;                            //For winsock initialization
                SOCKET ServerSocket = INVALID_SOCKET;       //Socket for communicating with server
                struct addrinfo *result = NULL;             //struct to hold address information
                struct addrinfo *Pointer = NULL;            //struct to hold point to next ip
                struct addrinfo address;                    //struct to hold connection information
                char recvbuf1[BUFLEN];                      //Buffer for receiving information
                char recvbuf2[BUFLEN];                      //Extra Buffer for receiving information
                char sendbuf[BUFLEN];                       //Buffer for sending information
                // Initialize Winsock
                status = WSAStartup(MAKEWORD(2, 2), &wsaData);
                if (status != 0)
                {
                    cout << "failed to initialize winsock" << endl;
                    _getch();
                    return 1;
                }
                ZeroMemory(&address, sizeof(address));
                address.ai_family = AF_INET;
                address.ai_socktype = SOCK_STREAM;
                address.ai_protocol = IPPROTO_TCP;
                address.ai_flags = AI_PASSIVE;
                //Get IP and port info
                status = getaddrinfo(argv[1], PORT, &address, &result);
                if (status != 0)
                {
                    cout << "getaddrinfo failed with error: " << WSAGetLastError() << endl;
                    freeaddrinfo(result);
                    _getch();
                    return 1;
                }
                // Attempt to connect to an address until one succeeds
                for (Pointer = result; Pointer != NULL; Pointer = Pointer->ai_next) {
                    // Create a SOCKET for connecting to server
                    ServerSocket = socket(Pointer->ai_family, Pointer->ai_socktype, Pointer->ai_protocol);
                    if (ServerSocket == INVALID_SOCKET) 
                    {
                        printf("socket failed with error: %ldn", WSAGetLastError());
                        WSACleanup();
                        _getch();
                        return 1;
                    }
                    // Connect to server.
                    status = connect(ServerSocket, Pointer->ai_addr, (int)Pointer->ai_addrlen);
                    if (status == SOCKET_ERROR) 
                    {
                        closesocket(ServerSocket);
                        ServerSocket = INVALID_SOCKET;
                        continue;
                    }
                    break;
                }

                if (ServerSocket == INVALID_SOCKET)
                {
                    cout << "could not connect " << endl;
                    _getch();
                    return 1;
                }
                else
                    cout << "connected to " << argv[1] << ":" << PORT << endl;
                //Done with the results
                freeaddrinfo(result);
                //set up game...
                //Grids that will be displayed
                char HitGrid[8][8];
                char ShipGrid[8][8];
                //Initialize grids
                InitGrid(HitGrid, ships);
                InitGrid(ShipGrid, ships);
                //Initialize ship hitboxes
                for (int x = 0; x <5; x++)
                {
                    //Initialize hitbox
                    for (int i = 0; i<5; i++)
                        ships[x].Hitbox[i] = Letter[x];
                }
                //Randomize ship locations
                PlaceShips(ships, ShipGrid);
                status = 1;
                while (status > 0)
                {
                    //Ask for cords 
                    cout << "Enter a coord to bomb or press v to view grid" << endl;
                    cin.getline(sendbuf, BUFLEN, 'n');

                    //If user type 'v' then display grids
                    while (strcmp(sendbuf, "V") == 0 || strcmp(sendbuf, "v") == 0)
                    {
                        //Display the grids
                        DisplayGrid(HitGrid, ShipGrid);
                        //Ask for cords 
                        cout << endl << "Enter a coord to bomb or press v to view grid" << endl;
                        cin.getline(sendbuf, BUFLEN, 'n');
                    }
                    //send cords
                    send(ServerSocket, sendbuf, BUFLEN, 0); 
                    //recv hit/miss
                    status = recv(ServerSocket, recvbuf1, BUFLEN, 0);
                    //If we hit a ship, mark it on the hit grid
                    if (recvbuf1[0] == 'H')
                    {
                        //Recieve ship that was hit
                        status = recv(ServerSocket, recvbuf2, BUFLEN, 0);
                        //Display shipname
                        for (int x = 0; x < status; x++)
                        {
                            cout << recvbuf2[x];
                        }
                        cout << " was hit!" << endl;
                        //Update the hit grid
                        HitGrid[(sendbuf[1] - 48)][(TransLettoNumb(sendbuf) -1)] = recvbuf2[0];
                    }
                    else
                    {
                        HitGrid[(sendbuf[1] - 48)][(TransLettoNumb(sendbuf) - 1)] = 'X';
                        //Display hit/miss
                        for (int x = 0; x < status; x++)
                        {
                            cout << recvbuf1[x];
                        }
                        cout << endl;
                    }
                    //recv cord
                    status = recv(ServerSocket, recvbuf1, BUFLEN, 0);
                    cout << endl << "server bombed cord " << recvbuf1[0] << recvbuf1[1] << endl;
                    //Check if it was a hit or miss and reply to server
                    if (!Checkhit(ships, recvbuf1, ShipGrid))
                        sendl(ServerSocket, false);
                    else
                    {
                        sendl(ServerSocket, true);
                        //Add to hit counter
                        HitCounter++;
                    }
                    //update the ship grid
                    ShipGrid[(recvbuf1[1] - 48)][(TransLettoNumb(recvbuf1) - 1)] = 'X';
                    //Clear buffer
                    memset(recvbuf1, 0, sizeof(recvbuf1));
                    memset(recvbuf2, 0, sizeof(recvbuf2));
                    if (HitCounter > 17)
                    {
                        cout << endl << "the server one the game!" << endl;
                        _getch();
                        return 0;
                    }
                }
                _getch();
                return 0;
            }

从我的经验来看,移植一个socket程序到ubuntu应该不是什么大问题,反之亦然。

我能给你的第一个建议是将(特定于操作系统的)套接字代码与游戏代码分开。我的建议是为此创建单独的类。

接下来,头文件conio.h, winsock2.h, windows.h和ws2tcpip.h在ubuntu(和一般Linux)中不存在,但函数存在于不同的头文件中。看看下面的教程,我非常喜欢。它解释了一个完整的教程:http://www.linuxhowtos.org/C_C++/socket.htm

希望能有所帮助