Что касается сокета C ++, почему сервер всегда возвращает один и тот же результат? - PullRequest
1 голос
/ 23 сентября 2019
#include <WinSock2.h>
#include <cstdlib>
#include <cstdio>
#include <inaddr.h>

int calculate(int aopNum, int aopVal[], char aop) {
    int result = aopVal[0], i;

    switch(aop)
    {
        case '+':
            for(i = 1; i < aopNum; i++) result += aopVal[i];
            break;
        case '-':
            for(i = 1; i < aopNum; i++) result -= aopVal[i];
            break;
        case '*':
            for(i = 1; i < aopNum; i++) result *= aopVal[i];
            break;
    }

    return result;
}

int main() {
    WSADATA wsadata;

    const int bufSize = 1000;
    const int opSize = 4;
    int port = 5099;
   // int result;

    if(WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
        printf("Failed to init\n");
        return -1;
    } else {
        printf("Inited \n");
    }

    SOCKADDR_IN addrServ;
    addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    addrServ.sin_family = AF_INET;
    addrServ.sin_port = htons(port);

    SOCKET  sockServ = socket(AF_INET, SOCK_STREAM, 0);

    if(bind(sockServ, (SOCKADDR *)&addrServ, sizeof(SOCKADDR)) == SOCKET_ERROR) {
        printf("Fail to bind \n");
    } else {
        printf("Binded \n");
    }

    if(listen(sockServ, 10) == SOCKET_ERROR) {
        printf("Fail to listen \n");
    } else {
        printf("Listening \n");
    }
    fflush(stdout);
    SOCKADDR_IN addrClnt;
    int len = sizeof(addrClnt);

 //   SOCKET sockClnt = socket(AF_INET, SOCK_STREAM, 0);

    char bufRecv[bufSize];
    int  opnum;
    int recvLen = 0;

 //   SOCKET sockClnt;
    while(1) {
        SOCKET sockClnt = accept(sockServ, (SOCKADDR *)&addrClnt, &len);
        if(sockClnt == SOCKET_ERROR) {
            printf("Fail to accept \n");
            return -1;
        } else {
            printf("Accepted \n");
        }
        fflush(stdout);
        recv(sockClnt, (char *)&opnum, 1, 0);
        //int opnum = (int)(copnum - '0');
        printf("%d\n", opnum);
        fflush(stdout);
        while((opSize * opnum + 1) > recvLen) {
            int len1 = recv(sockClnt, &bufRecv[recvLen], bufSize - 1, 0);
            recvLen += len1;
        }
        printf("%c\n", bufRecv[recvLen - 1]);
        fflush(stdout);
    //testbegin:
        int *p = (int *)bufRecv;
        for(int j = 0; j < opnum; j++) {
            printf("%d ", p[j]);
            fflush(stdout);
        }


        int result = calculate(opnum, (int *)bufRecv, bufRecv[recvLen - 1]);
        printf("%d\n", result);
        fflush(stdout);
        send(sockClnt, (char *)&result, sizeof(result), 0);
        closesocket(sockClnt);
    }

    //closesocket(sockClnt);
    WSACleanup();
    return 0;
}

client.cpp:

#include <WinSock2.h>
#include <cstdlib>
#include <cstdio>
#include <inaddr.h>

int main() {
    WSADATA wsadata;

    const int bufSize = 1000;
    const int opSize = 4;

    int opNum;
    int port = 5099;
    int result;
//    char cresult;
    if(WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
        printf("Fail to init \n");
        return -1;
    }

    SOCKADDR_IN servAddr;
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(port);
    servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    SOCKET sockClnt = socket(AF_INET, SOCK_STREAM, 0);

    if(connect(sockClnt, (SOCKADDR *)&servAddr, sizeof(servAddr)) != 0) {
        printf("Fail to connect \n");
    } else {
        printf("Connected \n");
    }
    fflush(stdout);
    char bufSent[bufSize];

    printf("Input the num of numbers: \n");
    fflush(stdout);
    scanf("%d", &opNum);
    bufSent[0] = (char)opNum;
    printf("Input the numbers \n");
    fflush(stdout);
    for(int i = 0; i < opNum; i++) {
        scanf("%d", (int *)&bufSent[1 + i * opSize]);
    }
    fgetc(stdin); 
    printf("Input the operator: \n");
    fflush(stdout);
    scanf("%c", &bufSent[1 + opNum * opSize]);

    send(sockClnt, bufSent, opNum * opSize + 2, 0);
    recv(sockClnt, (char *)&result, sizeof(result), 0);

    printf("The result is %d", result);
    fflush(stdout);
   // delay(5);
    closesocket(sockClnt);
    WSACleanup();
    return 0;
}

Проблема в том, что после запуска сервера я запустил клиент и ввел:

3
2
4
6
*

Он может вернуть 2 * 4 * 6 = 48 правильно,Однако, когда я запускаю новый клиент без остановки сервера, я ввожу:

3 
2
4
6
+

, и он по-прежнему возвращает 48 (вместо 2 + 4 + 6 = 12, даже если я ввожу 3 1 2 3, он по-прежнему возвращает 48),Я много пробовал, но до сих пор не могу решить.Поэтому сейчас я прошу помощи.

1 Ответ

1 голос
/ 23 сентября 2019

Эта переменная recvLen должна быть перемещена в цикл while (1):

while (1) {
int recvLen = 0;

она содержит значение из предыдущего соединения, а расположение значений / операторов неясно (не проверялэто полностью).После многих подключений код завершится сбоем и без этого изменения (указатель буфера всегда перемещается, буфер является статическим массивом в стеке)

Строка

recv(sockClnt, (char *)&opnum, 1, 0);

опасна .. она читаетодин байт в целое число.3 байта этого int не затронуты и содержат, вероятно, неинициализированную память.Лучше было бы передать целое число (4 байта) или, по крайней мере, переменная должна быть установлена ​​в 0:

int  opnum = 0;
...