关于C ++套接字,为什么服务器总是返回相同的结果?

时间:2019-09-23 11:47:47

标签: c++ sockets c++11 winsock2

#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,它也返回48(而不是3 1 2 3)。我尝试了很多,但仍然无法解决。所以我现在在这里寻求帮助。

1 个答案:

答案 0 :(得分:1)

应将recvLen变量移至while(1)循环中:

while (1) {
int recvLen = 0;

它包含来自先前连接的值,并且值/运算符的位置不清楚(没有完全检查它)。经过多次连接后,如果不进行更改,代码也将崩溃(缓冲区指针始终移动,缓冲区是堆栈上的静态数组)

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

是危险的..它将单个字节读取为整数。该int的3个字节不受影响,并且可能包含未初始化的内存。最好是传输一个整数(4个字节),或者至少将变量设置为0:

int  opnum = 0;