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++ 中将字节数组转换为十六进制字符串?