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

时间:2014-12-29 08:50:32

标签: 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;
}

3 个答案:

答案 0 :(得分:4)

汉斯说的话。加上这个:

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

你可能想说这个:

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

此外,你正在犯一个很多人用套接字制作的根本错误。您假设您的服务器上的recv调用将返回由客户端传递给相应的send调用的字节数。碎片,分段和其他网络内容可能会导致您只接收在其他节点send呼叫上发送的部分消息。 (因此,TCP是他们所说的流协议)。

您应该努力检查recv的返回值。编写代码,就像发送方一次只发送1个字节一样。您应该在消息之间放置分隔符(空字符很好)并在recv上循环,直到您收到完整的消息。否则,当你部署到互联网上时,在你自己的PC和本地子网上工作正常的东西会有奇怪的错误。

答案 1 :(得分:2)

问题是

strlen(recvbuf)

你可能意味着

sizeof(recvbuf)

strlen(recvbuf)没有意义之前你收到数据,因为你的缓冲区只包含垃圾,因此strlen()只是一个坏的随机数生成器。 strlen(recvbuf)有意义之后你收到数据,如果你确定它已经填满了0.不是这样,你可以使用recv()的返回值来找出你收到了多少字节。

答案 2 :(得分:2)

在服务器文件更改

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

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

更改是要接收的日期的长度