【问题标题】:About C++ socket, why does server always return the same result?关于C++ socket,为什么server总是返回相同的结果?
【发布时间】:2019-09-23 11:47:47
【问题描述】:
#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)。我尝试了很多但仍然无法解决它。所以我现在在这里寻求帮助。

【问题讨论】:

  • "我尝试了很多,但仍然无法解决" 您是否尝试在执行的每个步骤中使用调试器单步执行您的代码,调查变量的值,但是?
  • 谢谢你的建议,我会试试的:)
  • 打印计算函数中的数字和运算符,以验证它们是否是您认为的那样。在不通过网络的情况下测试您的功能。
  • 并且,也许,重置连接之间的服务器状态(opnumrecvLen 以及其他变量的值可能会在以前的连接中保留)。
  • 我刚学会在 clion 上使用 gdb,这是一个非常好的发现错误的方法,而不是只盯着代码。

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


【解决方案1】:

recvLenvariable 应该移到 while(1) 循环中:

while (1) {
int recvLen = 0;

它包含来自先前连接的值,并且值/运算符的位置不清楚(没有完全检查)。在多次连接后,代码也会崩溃而没有这种变化(缓冲区指针总是移动,缓冲区是堆栈上的静态数组)

线

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

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

int  opnum = 0;

【讨论】:

  • 非常感谢,问题解决了。我会去学习如何逐步调试:)
猜你喜欢
  • 2015-06-22
  • 2017-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-27
  • 1970-01-01
  • 2017-03-13
  • 1970-01-01
相关资源
最近更新 更多