c++ - 通过套接字发送数据不起作用

标签 c++ sockets networking network-programming client-server

我正在尝试通过套接字制作国际象棋游戏。 有一个服务器负责将棋盘发送给玩家,获取输入和响应等等。 我试图创建一个客户端服务器(实际上是 2 个客户端和服务器),但它不起作用。 客户端正确连接到服务器,但传送的数据不正确。 例如,我从客户端发送“E2-C3”; recv 结果(在服务器端)始终为 0,或者打印垃圾。

客户:

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sys/types.h>

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

using namespace std;


#define SERVER_IP "1.1.1.1"
#define SERVER_PORT 8888
#define BUFFER_SIZE 1024

// server side 
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30

// client side
#define MOVE 10

int __cdecl main()
{
    WSADATA info;
    int errorDATA; // configuriation 
    int socketCreate; // create the socket - empty
    SOCKADDR_IN ClientService; // configuriation (stage 3) - data of the server.
    int connectResult;
    char sendBuf[1024], recvbuf[1024];
    int iResult;

    /*Configuration*/
    errorDATA = WSAStartup(MAKEWORD(2, 2), &info);
    if (errorDATA == INVALID_SOCKET)
    {
        printf("WSAStartup failed with error : %d\n", errorDATA);
        return -1;
    }
    /*Create empty socket*/
    socketCreate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // creating the socket "Clean - empty"
    if (socketCreate == INVALID_SOCKET)
    {
        printf("Error number %d in creating socket!\n", WSAGetLastError());
        return -1;
    }
    printf("Creating socket SUCCEEDED!\n");

    /*Confugirate the created socket*/
    ClientService.sin_family = AF_INET;
    ClientService.sin_addr.s_addr = inet_addr(SERVER_IP); // server's ip
    ClientService.sin_port = htons(SERVER_PORT);

    /*Asking for connection*/
    connectResult = connect(socketCreate, (struct sockaddr*) &ClientService, sizeof(ClientService));

    while (1)
    {
        cout << "Please enter a move : " << endl;
        cin >> sendBuf;
        iResult = send(socketCreate, sendBuf, (int)strlen(sendBuf), 0);
        if (iResult == SOCKET_ERROR) {
            printf("send failed with error: %d\n", WSAGetLastError());
            closesocket(socketCreate);
            WSACleanup();
            return 1;
        }
        // MOVE 
        iResult = recv(socketCreate, recvbuf, strlen(recvbuf), 0);
        if (iResult > 0)
        {
            if (recvbuf[0] == '0' && recvbuf[1] == '0')
            {
                cout << "You've entered an illegal move. Please try again." << endl;
                continue;
            }
            else if (recvbuf[0] == '2' && recvbuf[1] == '0')
            {
                // print the board.
                bool keepGoing = 0;
                do
                {
                    iResult = recv(socketCreate, recvbuf, strlen(recvbuf), 0);
                    if (iResult > 0)
                    {
                        if (recvbuf[0] == '1' && recvbuf[1] == '5')
                        {
                            keepGoing = true;
                            continue;
                        }
                    }
                } while (!keepGoing);
            }
        }
        else if (iResult == 0)
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());
    }


    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(socketCreate, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(socketCreate);
        WSACleanup();
        return 1;
    }


    // cleanup
    closesocket(socketCreate);
    WSACleanup();

    cin.get();
    system("pause");
    return 0;
}

服务器:

#include <iostream>
#include <winsock2.h>
#include <string>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")

#define MAX_NUMBER_OF_PLAYERS 1
#define BUFFER_SIZE 1024
#define LIMIT 1

// server side 
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30

// client side
#define MOVE 10


using namespace std;

int main()
{
    WSADATA WsaDat;
    SOCKET clientsock[2];
    int minsock = 0;
    int numsocks = MAX_NUMBER_OF_PLAYERS;
    if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
    {
        std::cout << "WSA Initialization failed!\r\n";
        WSACleanup();
        system("PAUSE");
        return 0;
    }

    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (serverSocket == INVALID_SOCKET)
    {
        std::cout << "Socket creation failed.\r\n";
        WSACleanup();
        system("PAUSE");
        return 0;
    }

    SOCKADDR_IN serverInf;
    serverInf.sin_family = AF_INET;
    serverInf.sin_addr.s_addr = INADDR_ANY;
    serverInf.sin_port = htons(8888);

    if (bind(serverSocket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
    {
        std::cout << "Unable to bind socket!\r\n";
        WSACleanup();
        system("PAUSE");
        return 0;
    }

    listen(serverSocket, 5);


    clientsock[0] = accept(serverSocket, NULL, NULL);
    cout << "Client 1 has connected." << endl;
    clientsock[1] = accept(serverSocket, NULL, NULL);
    cout << "Client 2 has connected." << endl;

    for (int i = 0; i < 2; i++)
    {
        cout << clientsock[i] << endl;
    }

    // If iMode!=0, non-blocking mode is enabled.
    u_long iMode = 1;
    ioctlsocket(serverSocket, FIONBIO, &iMode);


    char client1_buffer[BUFFER_SIZE];
    char client2_buffer[BUFFER_SIZE];
    char* clientBuffer;
    // until there isn't a mate.
    bool gameRunning = true;
    // user represents if it's user1 (0), or user2(1)
    bool user = 0;


    while (gameRunning)
    {
        if (!user)
            clientBuffer = client1_buffer;
        else
            clientBuffer = client2_buffer;

        int in = recv(clientsock[0], client1_buffer, 0, 0);
        cout << in << endl;
        if (in > 0)
        {
                // CHECKS
                // MOVE COMMAND
                // IF worked, send the board to both clients. if current user = 1 ==> do user to 0 | if the user = 0 => do user to 11
                // ELSE, send the current client (clientsock[user]) Error message and ask for a command again.
            cout << client1_buffer << endl;
                cout << " IN RECV";
                char* szMessage = "15";
                send(clientsock[0], szMessage, strlen(szMessage), 0);
        }
        else if (in == 0)
        {
            // The connection has closed.
            // REMEMBER : SAVE THE GAME SITUATION.
        }
        else
        {
            printf("recv failed: %d\n", WSAGetLastError());
            // SEND ERROR MESSAGE TO BOTH CLIENTS
        }


    }
    // Shutdown our socket
    shutdown(serverSocket, SD_SEND);

    // Close our socket entirely
    closesocket(serverSocket);

    WSACleanup();
    system("pause");
    return 0;
}

最佳答案

汉斯说的。加上这个:

int in = recv(clientsock[0], client1_buffer, 0, 0);

你可能想这样说:

int in = recv(clientsock[0], client1_buffer, BUFFER_SIZE, 0);

此外,您犯了一个很多人在使用套接字时都会犯的基本错误。您假设服务器上的 recv 调用将返回客户端传递给相应 send 调用的字节数。分段、分段和其他网络内容可能会导致您仅收到在其他节点的 send 调用上发送的部分消息。 (因此,正如他们所说,TCP 是一种流协议(protocol))。

您应该认真检查 recv 的返回值。编写您的代码,就好像发件人一次只发送 1 个字节一样。您应该在消息之间放置定界符(可以使用空字符)并循环接收直到收到完整的消息。否则,在您自己的 PC 和本地子网上似乎运行良好的内容在部署到 Internet 时会出现奇怪的错误。

关于c++ - 通过套接字发送数据不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27685865/

相关文章:

java - java Socket类中的sendbuffersize可以设置多大?

networking - 从不在网络上的另一台计算机访问本地主机

ios - 如何在 NETunnelProviderManager 中找出 IP 流量的源进程

c++ - 精神语法解析问题

c++ - 不使用 USES_CONVERSION 宏

c++ - 数组的重载运算符

c++ - 我怎么知道 pthread_mutex_destroy 中的系统错误是什么?

javascript - 通过 JavaScript 连接到套接字(没有 flash)

有效网络掩码的 c 代码

c++ - 在 Linux 中将 fork() + execlp 与 boost::asio 一起使用时解决重用错误