【问题标题】:TCP server using select()使用 select() 的 TCP 服务器
【发布时间】:2015-03-22 09:31:15
【问题描述】:

我需要写一个可以处理多个连接的TCP服务器;我关注this guide并编写了以下程序:

static void _handle_requests(char* cmd,int sessionfd){
    //TODO: extend
    printf("RECEIVED: %s\n",cmd);
    if (!strcmp(cmd,BAR)){
        barrier_hit(&nodebar,sessionfd);

    }else if (!strcmp(cmd, BYE)){


    }else if (!strcmp(cmd, HI)){

    }
}

void handle_requests(void){
    listen(in_sock_fd,QUEUELEN);
    fd_set read_set, active_set;
    FD_ZERO(&active_set);
    FD_SET(in_sock_fd, &active_set);
    int numfd = 0;
    char cmd[INBUFLEN];
    for (;;){
        read_set = active_set;

        numfd = select(FD_SETSIZE,&read_set,NULL,NULL,NULL);
        for (int i = 0;i < FD_SETSIZE; ++i){
            if (FD_ISSET(i,&read_set)){ 
                if (i == in_sock_fd){
                    //new connection
                    struct sockaddr_in cliaddr;
                    socklen_t socklen = sizeof cliaddr;
                    int newfd = accept(in_sock_fd,(struct sockaddr*)&cliaddr, &socklen);
                    FD_SET(newfd,&active_set);  
                }else{
                    //already active connection
                    read(i,cmd,INBUFLEN);
                    _handle_requests(cmd,i);
                }
            }


        }
    }
}

..和一个连接() 到服务器并对套接字文件描述符执行两次连续 write() 调用的单个客户端。

n = write(sm_sockfd, "hi", 3);

    if (n < 0) {
        perror("SM: ERROR writing to socket");
        return 1;
    }

//...later

 n = write(sm_sockfd, "barrier", 8);


    if (n < 0) {
        perror("SM: 'barrier msg' failed");
        exit(1);
    }

问题是,服务器只接收第一条消息(“hi”);之后,选择呼叫挂起。由于客户端的写入(“屏障”)成功,该会话文件描述符不应该准备好读取吗?我犯了什么明显的错误吗?

谢谢;抱歉,如果这是显而易见的事情,我对 C 的网络库完全不熟悉,该项目很快就要到期了!

【问题讨论】:

    标签: c sockets networking tcp


    【解决方案1】:

    您对 TCP 套接字的工作方式存在误解。 TCP 没有消息边界,即如果先发送“hi”然后发送“barrier”,则不能指望相应的接收返回“hi”和“barrier”。他们可能会返回“hibarrier”。理论上也有可能(尽管非常罕见)它们会返回“h”、“i”、“b”、“a”、“r”、“r”、“i”、“e”、“r”。

    您确实需要考虑如何界定您的消息。一种可能性是在消息之前以网络字节顺序(4 个字节)将消息的长度作为 32 位整数发送。然后当你收到消息时,你首先读取 4 个字节,然后读取消息长度指示的字节数。

    请注意 TCP 可能会返回部分读取,因此您需要以某种方式处理这些。一种可能性是有一个缓冲区来保存读取的字节,然后在读取更多字节时附加到该缓冲区,并在缓冲区的前四个字节(即消息长度)表明您拥有完整的消息。

    如果您想要一个保留数据包边界的顺序数据包协议,您可能需要考虑 SCTP。但是,目前操作系统内核并没有广泛支持它,所以我要做的是在 TCP 之上有一个面向数据包的层的 32 位长度技巧。

    【讨论】:

      【解决方案2】:

      这样做:

      int nbrRead = read(i,cmd,INBUFLEN);
      

      并打印出 nbrRead 的值。你会看到你一口气收到了所有东西。 TCP 是一种流式传输协议,如果您进行 3 次或更多的连续发送,您将有很高的机会一次性收到它们。

      还要确保 INBUFLEN 足够大 2048 对于您的示例来说已经足够了。

      【讨论】:

        猜你喜欢
        • 2018-04-26
        • 1970-01-01
        • 2013-04-11
        • 1970-01-01
        • 2019-11-20
        • 2020-04-15
        • 2015-08-05
        • 1970-01-01
        • 2013-07-01
        相关资源
        最近更新 更多