【问题标题】:RECV buffer empty, but returns a value > 1RECV 缓冲区为空,但返回值 > 1
【发布时间】:2015-06-01 06:18:37
【问题描述】:

我正在尝试制作一个简单的服务器,以便两个客户端可以相互通信。主服务器代码接受两个客户端连接,然后分叉一个使用 execl 在两个客户端之间生成个人服务器的进程,以便主服务器可以继续寻找新连接。在个人服务器尝试联系客户并且他们都收到乱码之前,一切似乎都正常工作,如果有人知道可能导致这种情况的原因,请告诉我。

接受两个客户端后的主服务器:

if(fork() == 0){
        close(listener);
        int nBytes;
        char* playerOne[20];
        char* playerTwo[20];

        //Creates strings to hold file descriptor information for execl
        char connAscii[sizeof(int)];
        char connAscii2[sizeof(int)];
        snprintf(connAscii,sizeof(conn), "%d", conn);
        snprintf(connAscii2,sizeof(conn2), "%d", conn2);
        fprintf(stderr, "Int conn: %d, asciiConn: %s, backToInt: %d\n", conn, connAscii, atoi(connAscii));
        char *argf[2];
        argf[0] = connAscii; 
        argf[1] = connAscii2;
        fprintf(stderr, "that is to say %s and %s\n", argf[0], argf[1]);

        //Send Handle Request to Connection 1
        nBytes = send(conn, handleRequest, sizeof(handleRequest),0);
        if(nBytes == -1){
            perror("send");
            exit(1);
        }
        //Receive Handle from Connection 1
        nBytes = recv(conn, playerOne, 20, 0);
        if(nBytes == -1){
            perror("recv");
            exit(1);
        }
        //Send Handle Request to Connection 2
        nBytes = send(conn2, handleRequest, sizeof(handleRequest),0);
        if(nBytes == -1){
            perror("send");
            exit(1);
        }
        //Receive Handle from Connection 2
        nBytes = recv(conn2, playerTwo, 20, 0);
        if(nBytes == -1){
            perror("recv");
            exit(1);
        }
        //Send Handle for Connection 2 to Connection 1
        nBytes = send(conn, playerTwo, sizeof(playerTwo),0);
        if(nBytes == -1){
            perror("send");
            exit(1);
        }
        //Send Handle for Connection 1 to Connection 2
        nBytes = send(conn2, playerOne, sizeof(playerOne),0);
        if(nBytes == -1){
            perror("send");
            exit(1);
        }

        //Passes file descriptors to privateServer
        execl("privateServer","privateServer", connAscii, connAscii2, (char *)0); 
}

execl 调用的个人服务器:

char greet[] = {"Hello players, please wait for match setup."};
int main(int argc, char *argv[]) {
    int conn1 = atoi(argv[1]);
    int conn2 = atoi(argv[2]);
    int sent;
    fprintf(stderr, "Attempting connection with %d\n", conn1);
    sent = send(conn1, greet,sizeof(greet),0);
    if(sent == -1){
        perror("send");
        exit(1);
    }

    sent = send(conn2, greet,sizeof(greet),0);
    if(sent == -1){
        perror("send");
        exit(1);
    }
    fprintf(stderr,"Hopefully they got it\n");
    return 0;
    }

客户端:逐字符读取 recv buff 字符会导致乱码,打印整个缓冲区不显示任何内容,但 numbytes == 61。

char *buff = (char*)malloc(100);
memset(&buff[0],0,sizeof(buff));
numbytes = recv(sockfd, buff, 99, 0);  //should be from private server
if (numbytes == -1) {
        perror("recv");
        exit(1);
    }
buff[numbytes] = '\0';
int i;
for(i = 0; i < numbytes; i++){
    fprintf(stderr, "%c", buff[i]);
}
printf("From match server: %.*s (%d bytes)\n", numbytes, buff, numbytes);   

【问题讨论】:

  • char* playerOne[20]; --> char playerOne[20];,同样适用于playerTwo
  • 谢谢,我会解决这个问题,但是 playerOne 和 playerTwo 从主服务器发送到客户端没有问题,而我无法将消息从私有服务器发送到客户端 @AlterMann
  • 实际上解决了整个问题。这是一个多么美妙的世界,通过删除*来解决工作时间
  • 你还有问题,看我的回答
  • 关于在 C 中调用 malloc() 1) 不应强制转换返回值 2) 应始终检查返回值 (!=NULL) 以确保操作成功

标签: c client-server server send recv


【解决方案1】:

有几个错误:

char* playerOne[20];
char* playerTwo[20];

你想要一个字符数组,而不是一个字符指针数组

改成

char playerOne[20];
char playerTwo[20];

这里:

char *buff = (char*)malloc(100);
memset(&buff[0],0,sizeof(buff));

sizeof(buff)是指向char的指针的大小,改为

memset(&buff[0],0,100);

正如@user3629249 所指出的,不要使用像 100 这样的幻数,而是

#define MAX_BUFF 100
char *buff = malloc(MAX_BUFF);
memset(&buff[0],0,MAX_BUFF);

但如果您以空值终止字符串,则无需memset

【讨论】:

  • '100' 将是一个具有#define'd 值的绝佳位置,然后调试、维护和清晰度将大大提高。请记住,其他人需要了解您的代码。即使是你,在经过一段时间后,也会受益于有意义的#define 值“100”
  • 无论如何,memset 都是货物崇拜的垃圾。如果您要在接下来的几行中组装一个以 null 结尾的字符串,那是完全没有意义的。
  • 读取计数处的空终止也是货物崇拜编程。您应该传递recv(). 返回的读取计数您不能假设接收到的数据是文本并且应该以空值结尾,它会浪费接收缓冲区中的一个元素。如果您忘记了 -1,则会导致错误。
  • @EJP 哎呀,你是对的,出于某种原因,我认为这些变量已作为参数传递给 execl
猜你喜欢
  • 1970-01-01
  • 2010-12-17
  • 2011-01-12
  • 2012-04-04
  • 1970-01-01
  • 2012-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多