C++ linux套接字,在一次调用中将字符串数组(char**)作为连接字符串发送

Posted

技术标签:

【中文标题】C++ linux套接字,在一次调用中将字符串数组(char**)作为连接字符串发送【英文标题】:C++ linux socket that sends array of strings(char**) in a single call as concatenated string 【发布时间】:2013-10-31 13:46:49 【问题描述】:

我得到了一个冗长的字符串数组。我必须在send (int __fd, const void *__buf, size_t __n, int __flags) 调用中将它们作为单个连接字符串发送。恐怕它是一个消耗 CPU 的过程来构造单个连接字符串(char *)。是否可以将字符串数组尾部发送到头部?

只要recv 在接收端多次触发,我不想为单个有意义的字符串多次调用send

我想知道为什么C/C++ 中没有像链表这样的标准化可扩展字符串结构,以便读者可以在缓冲区末尾跳转到下一个缓冲区。我希望至少 std::string 实现这一点。

【问题讨论】:

看看writev 如果您没有使用send 中的标志,那么您可以使用fdopen 为您的套接字创建一个stdio 接口,然后只需fwrite,然后一一创建流。 @PlasmaHH 我在发送函数中使用了标志。 writev 可以吗? @neckTwi,忘记标头和数据包。您无法控制 TCP 如何将数据打包成数据包。小发送(到您的 pgm)的成本是系统调用的开销,与通过网络发送大数据的成本相比,这没有。在接收端,您无法控制接收到的数据如何到达。这就是 TCP 的本质。您必须进行多次读取并连接数据。 正如其他人所建议的,只需 send() 每个字符串。在 recv() 结尾解析出各个字符串(可能是通过搜索空终止符)。 TCP 字节流没有简单的替代方案。 【参考方案1】:

您无需一次性连接所有字符串。这不会非常消耗 CPU,因为它无论如何都会发生在下面,但它可能会也可能不会消耗大量内存。

如果您在send 中使用标志,那么您应该确定套接字缓冲区的大小。将您的字符串连接到该缓冲区大小,然后 send 他们一次一个缓冲区

void send_strings(int sockfd, char ** strings, size_t numstrings, int flags) 
    // get the socket write buffer size
    int buflen;
    unsigned int m = sizeof(bufsize);
    if(getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,(void *)&buflen, &m)) 
        perror("getsockopt"); return; 

    char buffer[buflen];
    int bufsize = 0;

    while (numstrings--) 
        char * string = *(strings++);
        size_t length = strlen(string);

        // if the string would exceed the buffer
        while (length > buflen - bufsize) 
            memcpy(buffer + bufsize, string, buflen - bufsize);

            length -= buflen - bufsize;
            string += buflen - bufsize;

            // send a full buffer
            send(sockfd, buffer, buflen, flags);
            bufsize = 0;
        
        // copy the string into the buffer
        memcpy(buffer + bufsize, string, length);
        bufsize += length;
    
    // send the rest
    if (bufsize) 
        send(sockfd, buffer, bufsize, flags);
    

【讨论】:

在接收端,我需要对单个字符串多次使用recv。所以我需要添加边界并在接收端解释它们。我有一个简单的解决方案吗?谢谢 @neckTwi - 不,除了可以在 recv() 端从 TCP 字节流重新组装字符串的应用程序级协议之外,别无选择。 @neckTwi 你说你只需要发送连接的字符串。如果你会说你需要编组它们,那么这是一个不同的故事。一种简单的方法是发送空终止符并使用它来区分接收端的字符串。如果您需要更复杂的编组方法,那么您也应该将其放入您的问题中。 @SergeyL。在我的问题中,我提到了in a single call @neckTwi 有什么原因吗?即使你做了一个调用,那么在send 的实现中,你的数据仍然会被分成套接字缓冲区大小的块。【参考方案2】:

http://linux.die.net/man/2/send 声明使用MSG_MORE 标志。设置后,只有在没有MSG_MORE 标志的send 调用之后才会启动传输。因此,除了最后一个数据块之外,使用MSG_MORE 为每个数据块调用send

【讨论】:

以上是关于C++ linux套接字,在一次调用中将字符串数组(char**)作为连接字符串发送的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Visual C++ 中将字节数组转换为十六进制字符串?

在 C++ 中将文件读入字符数组

如何在 C++ 中将字符串数组转换为整数数组?

如何在 C++ 中将数字字符串拆分为数组? [复制]

如何在 C++ 中将数字字符串转换为 int 数组 [重复]

如何在 C++ 中将字符串拆分为数组