// In server.cpp after connection has established
std::string input;
input.reserve(5);
std::cout << "Enter message to send: ";
std::cin.ignore(); // =====(1)=====
std::getline(std::cin, input);
std::cout << "Sending..." << std::endl;
auto len = input.length();
auto bytes_sent = send(newFD, input.data(), len, 0); // =====(2)=====
std::cout << "Input length : " << input.length() << std::endl
<< "Input bytes sent : " << bytes_sent << std::endl;
我的目标是在简单的 tcp客户端服务器程序中使用std::string
而不是普通的旧char[fixed]
。所以在server.cpp
我有两个疑问。到目前为止,我的初步猜测正如预期的那样。我在代码中将它们标记在上面。
cin.ignore()
vs cin.clear()
+ cin.sync()
std::string.data()
vs std::string.c_str()
我应该使用哪个?我甚至不确定其中任何一个的差异,我也不知道他们是否为我的问题做出了贡献。
// In client.cpp
std::string message;
message.reserve(5);
auto len = message.capacity();
auto bytes_recv = recv(sockFD, &message.front(), len - 1, 0); // =====(1)=====
message[len] = 0; // =====(2)=====
close(sockFD);
freeaddrinfo(res);
std::cout << "Bytes recieved :" << bytes_recv << std::endl;
std::cout << message.c_str() << std::endl; // =====(3)=====
在client.cpp中,当我尝试发送更大的字符串时,一切都会出错。但我可能知道原因,但解决方案实施起来有些棘手。
&std::string.front()
来写入传入的数据?&front()
,我猜length
无法获得更新,或者我不确定会发生什么,但输出{{}时数据肯定会丢失1}}。std::cout << message;
,如果返回的数据小于总长度,它仍会产生垃圾,可能是因为它无法在正确的位置找到终止字符?server.cpp
&front
// compile as 'g++ server.cpp -o server.app -std=c++14'
// run as : './server.app 8080'
client.cpp
#include <iostream> #include <string> #include <cstring> extern "C" { #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netdb.h> #include <arpa/inet.h> #include <netinet/in.h> } int main(int argc, char *argv[]) { if(argc != 2) { std::cerr << "Run program as 'program port'" << std::endl; return -1; } auto &portNum = argv[1]; const unsigned int backLog = 5; struct addrinfo hints, *res, *p; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; int gAddRes = getaddrinfo(NULL, portNum, &hints, &res); if(gAddRes != 0) { std::cerr << gai_strerror(gAddRes) << std::endl; return -2; } std::cout << "Detecting addresses" << std::endl; unsigned int numOfAddr = 0; char ipStr[INET6_ADDRSTRLEN]; for(p = res; p != NULL; p = p->ai_next) { void *addr; std::string ipVer = "IPv0"; if(p->ai_family == AF_INET) { ipVer = "IPv4"; struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; addr = &(ipv4->sin_addr); ++numOfAddr; } else { ipVer = "IPv6"; struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; addr = &(ipv6->sin6_addr); ++numOfAddr; } inet_ntop(p->ai_family, addr, ipStr, sizeof(ipStr)); std::cout << "(" << numOfAddr << ") " << ipVer << " : " << ipStr << std::endl; } if(!numOfAddr) { std::cerr << "Found no host address to use" << std::endl; return -3; } std::cout << "Enter the number of host address to bind with:" << std::endl; unsigned int choice = 0; bool madeChoice = false; do { std::cin >> choice; if(choice > (numOfAddr + 1) || choice < 1) { madeChoice = false; std::cout << "Wrong choice, try again!" << std::endl; } else madeChoice = true; } while(!madeChoice); p = res; bool isIPv4 = true; if(choice > 1) { unsigned int temp = 1; while(choice < temp) { p = p->ai_next; ++temp; } if(p->ai_family == AF_INET) { isIPv4 = true; } else isIPv4 = false; } int sockFD = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if(sockFD == -1) { std::cerr << "Error while creating socket" << std::endl; freeaddrinfo(res); return -4; } int bindR = bind(sockFD, p->ai_addr, p->ai_addrlen); if(bindR == -1) { std::cerr << "Error while binding socket" << std::endl; close(sockFD); freeaddrinfo(res); return -5; } int listenR = listen(sockFD, backLog); if(listenR == -1) { std::cerr << "Error while Listening on socket" << std::endl; close(sockFD); freeaddrinfo(res); return -6; } struct sockaddr_storage client_addr; socklen_t client_addr_size = sizeof(client_addr); int newFD = accept(sockFD, (struct sockaddr *)&client_addr, &client_addr_size); if(newFD == -1) { std::cerr << "Error while Accepting on socket" << std::endl; close(sockFD); freeaddrinfo(res); return -7; } std::string input; input.reserve(5); std::cout << "Enter message to send: "; std::cin.ignore(); std::getline(std::cin, input); std::cout << "Sending..." << std::endl; auto len = input.length(); auto bytes_sent = send(newFD, input.data(), len, 0); std::cout << "Input length : " << input.length() << std::endl << "Input bytes sent : " << bytes_sent << std::endl; close(newFD); close(sockFD); freeaddrinfo(res); return 0; }
// compile as 'g++ client.cpp -o client.app -std=c++14'
// run as : './client.app 0 8080'
答案 0 :(得分:3)
您的问题太过模糊,无法提供有用的答案。
data()
和c_str()
是effectively the same thing。你使用哪一个并不重要。 编辑:In C++17, data()
will have a non-const
overload that returns a non-const
char*
,因此您无需&message.front()
访问可修改形式的底层缓冲区。 c_str()
将保持const
。
&message.front()
是对的......错了。这是获取char*
内容的非常量std::string
的方法。但是message
未初始化,并且代码中的size()
0
reserve(5)
,因此我甚至不确定代码行是否是明确定义的行为。而不是string
我会像auto message = std::string(5, ' ');
那样构建你的recv
然后当你将它传递到message
时,那里实际上会有有效的东西可以覆盖它,你和#39;之后可以从len
阅读。
是的,这是错误的。您应该将字符串设置为您需要的实际大小。我怀疑如果你这样做,你可以传递len - 1
而不是c_str()
。关于这个话题,你确定你所收到的一切只有4个字节吗?或者你是否故意一次只读4个字节?
a)您不需要将std::cout
传递给<<
。 std::string
已超载以接受recv
。 b)message
返回您收到的字节数。如果该值小于您将' '
初始化为的值,则字符串中的其余字符将为垃圾(或char
message.resize(bytes_recv);
s,如果您遵循我的建议:#3 )。收到邮件后我会<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:key name="version" match="foo" use="@version"/>
<xsl:key name="item" match="foo/bar/item" use="@key"/>
<xsl:variable name="vers2" select="key('version', '2.0.0')"/>
<xsl:variable name="k1" select="key('item', 'k1', $vers2)"/>
<xsl:variable name="data1" select="$k1/data[starts-with(., 'abc')]"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="$data1|
$k1/text()[not(normalize-space())][some $d in $data1 satisfies ($d is following-sibling::node()[1])]"/>
</xsl:transform>
。
答案 1 :(得分:2)
您的问题已通过大写字母解决,但我的2美分。如何拥有自己的发送/接收功能并隐藏复杂性?
例如:
ssize_t recv(int sockfd, std::string &buf, size_t len, int flags) {
buf.resize(len); // current status unknown -> make it fit
ssize_t n = ::recv(sockfd, (void *)buf.data(), len, flags);
buf.resize(n >= 0 ? n : 0); // take error into account
return n;
}