这是一个简单的例子
c_str()
在带有 nul-chars 的字符串上显示的问题。
- 用于发送/接收字符串的两个原语。
这个想法是在实际字符之前的固定字节数上发送/接收字符串的长度。
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <iostream>
#include <string>
#include <stdexcept>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
ssize_t
send_all(int sockfd,
const void *buf,
size_t len,
int flags)
{
const auto *p=static_cast<const char *>(buf);
auto remaining=len;
while(remaining)
{
const auto r=send(sockfd, p, remaining, flags);
if(r<0)
{
return r;
}
remaining-=r;
p+=r;
}
return len-remaining;
}
ssize_t
recv_all(int sockfd,
void *buf,
size_t len,
int flags)
{
char *p=static_cast<char *>(buf);
auto remaining=len;
while(remaining)
{
const auto r=recv(sockfd, p, remaining, flags);
if(r<0)
{
return r;
}
if(r==0) // EOF
{
break;
}
remaining-=r;
p+=r;
}
return len-remaining;
}
void
send_string(int sockfd,
const std::string &str,
int flags)
{
const auto length=htonl(std::int32_t(size(str)));
if(send_all(sockfd, &length, sizeof(length), flags)!=sizeof(length))
{
throw std::runtime_error{"cannot send length"};
}
if(send_all(sockfd, data(str), size(str), flags)!=
static_cast<ssize_t>(size(str)))
{
throw std::runtime_error{"cannot send string"};
}
}
std::string
recv_string(int sockfd,
int flags)
{
auto str=std::string{};
auto length=std::int32_t{};
const auto r=recv_all(sockfd, &length, sizeof(length), flags);
if(r==0) // EOF
{
return str;
}
if(r!=sizeof(length))
{
throw std::runtime_error{"cannot receive length"};
}
str.resize(ntohl(length));
if(recv_all(sockfd, data(str), size(str), flags)!=
static_cast<ssize_t>(size(str)))
{
throw std::runtime_error{"cannot receive string"};
}
return str;
}
int
main()
{
auto msg=std::string{};
msg+="there is a nul-char...";
msg+='\0';
msg+="in the middle!";
std::cout << "as a string <" << msg << ">\n";
std::cout << "as a const char * <" << msg.c_str() << ">\n";
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
int fd[2];
if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fd)<0)
{
throw std::runtime_error{"socketpair() failure"};
}
for(auto i=0; i<5; ++i) // very few to fit in internal buffer
{
send_string(fd[1], "message number "+std::to_string(i+1), 0);
}
close(fd[1]);
for(;;)
{
const auto s=recv_string(fd[0], 0);
if(empty(s))
{
break;
}
std::cout << '[' << s << "]\n";
}
close(fd[0]);
return 0;
}
/**
as a string <there is a nul-char...in the middle!>
as a const char * <there is a nul-char...>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[message number 1]
[message number 2]
[message number 3]
[message number 4]
[message number 5]
**/