我是TCP客户端/服务器通信的新手。我正在尝试在服务器的循环中发送输出,并在客户端接收它。
我的问题是,我在客户端得到随机值作为输出。
我已经分享了我的服务器和客户端片段:
server.cpp
string r_n, r_n1, r_n2, r_n3, r_n4, r_n5, r_n6, r_n7, r_n8, r_n9;
for (result::const_iterator c = R.begin(); c != R.end(); ++c) {
r_n = c[0].as<int>();
r_n1 = c[1].as<string>();
r_n2 = c[2].as<string>();
r_n3 = c[3].as<string>();
r_n4 = to_string(c[4].as<long long int>());
r_n5 = c[5].as<string>();
r_n6 = c[6].as<string>();
r_n7 = c[7].as<string>();
r_n8 = to_string(c[8].as<int>());
r_n9 = to_string(c[9].as<int>());
send(serverSocket, r_n.c_str(), sizeof(r_n), 0);
send(serverSocket, r_n1.c_str(), sizeof(r_n1), 0);
send(serverSocket, r_n2.c_str(), sizeof(r_n2), 0);
send(serverSocket, r_n3.c_str(), sizeof(r_n3), 0);
send(serverSocket, r_n4.c_str(), sizeof(r_n4), 0);
send(serverSocket, r_n5.c_str(), sizeof(r_n5), 0);
send(serverSocket, r_n6.c_str(), sizeof(r_n6), 0);
send(serverSocket, r_n7.c_str(), sizeof(r_n7), 0);
send(serverSocket, r_n8.c_str(), sizeof(r_n8), 0);
send(serverSocket, r_n9.c_str(), sizeof(r_n9), 0);
}
client.cpp
int i = 0;
while (i < 4)
{
recv(TCPClientSocket, RecvBuffer, sizeof(RecvBuffer), 0);
recv(TCPClientSocket, RecvBuffer1, sizeof(RecvBuffer1), 0);
recv(TCPClientSocket, RecvBuffer2, sizeof(RecvBuffer2), 0);
recv(TCPClientSocket, RecvBuffer3, sizeof(RecvBuffer3), 0);
recv(TCPClientSocket, RecvBuffer4, sizeof(RecvBuffer4), 0);
recv(TCPClientSocket, RecvBuffer5, sizeof(RecvBuffer5), 0);
recv(TCPClientSocket, RecvBuffer6, sizeof(RecvBuffer6), 0);
recv(TCPClientSocket, RecvBuffer6, sizeof(RecvBuffer6), 0);
recv(TCPClientSocket, RecvBuffer7, sizeof(RecvBuffer7), 0);
recv(TCPClientSocket, RecvBuffer8, sizeof(RecvBuffer8), 0);
recv(TCPClientSocket, RecvBuffer9, sizeof(RecvBuffer9), 0);
cout << "t" << RecvBuffer << "t" << RecvBuffer1 << "t" << RecvBuffer2 << "t" << RecvBuffer3;
cout << "t" << RecvBuffer4 << "t" << RecvBuffer5 << "t" << RecvBuffer6 << "t" << RecvBuffer7 << "t" << RecvBuffer8 << "t" << RecvBuffer9 << endl;
cout << endl;
i++;
}
客户端输出:
102 AC First shek 9944833930 Chennai 2022-05-21 6 1000
TCP是字节流,它没有消息边界的概念,所以你必须明确数据本身的数据大小。或者在发送数据之前发送数据的大小,或者在数据之后发送一个唯一的结束符。
您的string
数据是可变长度的,但是您没有以任何方式分隔您的字符串,因此客户端无法知道实际发送了多少数据,甚至无法知道哪个数据属于哪个字符串。
当通过send()
发送string
时,sizeof()
是错误的缓冲区大小。您需要使用字符串的size()
方法。您还需要注意send()
的返回值,因为它告诉您实际接受了多少字节用于发送,其中可能(并且通常是)小于请求的字节数。recv()
也一样。因此,您需要在循环中调用这两个函数,直到发送/接收到预期的字节数。此外,recv()
的输出不是以空结束的,但您的代码期望它是。
说了这些,试着这样做:
server.cpp
void sendRaw(int socket, const void *data, size_t size)
{
const char *ptr = reinterpret_cast<const char*>(data);
while (size > 0)
{
int numSent = send(socket, ptr, size, 0);
if (numSent < 0) throw ...;
ptr += numSent;
size -= numSent;
}
}
void sendUInt32(int socket, uint32_t value)
{
value = htonl(value);
sendRaw(socket, &value, sizeof(value));
}
void sendString(int socket, const string &str)
{
uint32_t size = str.size();
sendUInt32(socket, size);
sendRaw(socket, str.c_str(), size);
}
...
string n_r[10];
sendUInt32(serverSocket, R.size());
for (result::const_iterator c = R.begin(); c != R.end(); ++c) {
n_r[0] = to_string(c[0].as<int>();
n_r[1] = c[1].as<string>();
n_r[2] = c[2].as<string>();
n_r[3] = c[3].as<string>();
n_r[4] = to_string(c[4].as<long long int>());
n_r[5] = c[5].as<string>();
n_r[6] = c[6].as<string>();
n_r[7] = c[7].as<string>();
n_r[8] = to_string(c[8].as<int>());
n_r[9] = to_string(c[9].as<int>());
for(int i = 0; i < 10; ++i) {
sendString(serverSocket, n_r[i]);
}
}
client.cpp
void recvRaw(int socket, void *data, size_t size)
{
char *ptr = reinterpret_cast<char*>(data);
while (size > 0)
{
int numRecvd = recv(socket, ptr, size, 0);
if (numRecvd <= 0) throw ...;
ptr += numRecvd;
size -= numRecvd;
}
}
uint32_t recvUInt32(int socket)
{
uint32_t value;
recvRaw(socket, &value, sizeof(value));
return ntohl(value);
}
string recvString(int socket)
{
string str;
uint32_t size = recvUInt32(socket);
if (size > 0)
{
str.resize(size);
recvRaw(socket, str.data(), size);
}
return str;
}
...
string r_n[10];
uint32_t count = recvUInt32(TCPClientSocket);
for(uint32_t i = 0; i < count; ++i)
{
for (int i = 0; i < 10; ++i) {
r_n[i] = recvString(TCPClientSocket);
}
for (int i = 0; i < 10; ++i) {
cout << 't' << r_n[i];
}
cout << endl << endl;
}
也就是说,一些输出字段最初是整数而不是字符串,所以最好将它们作为整数而不是字符串发送,例如:
server.cpp
void sendRaw(int socket, const void *data, size_t size)
{
const char *ptr = reinterpret_cast<const char*>(data);
while (size > 0)
{
int numSent = send(socket, ptr, size, 0);
if (numSent < 0) throw ...;
ptr += numSent;
size -= numSent;
}
}
void sendUInt32(int socket, uint32_t value)
{
value = htonl(value);
sendRaw(socket, &value, sizeof(value));
}
void sendInt32(int socket, int32_t value)
{
value = htonl(value);
sendRaw(socket, &value, sizeof(value));
}
void sendInt64(int socket, int64_t value)
{
value = htonll(value); // or whatever equivalent your environment provides
sendRaw(socket, &value, sizeof(value));
}
void sendString(int socket, const string &str)
{
uint32_t size = str.size();
sendUInt32(socket, size);
sendRaw(socket, str.c_str(), size);
}
...
int n_r, n_r8, n_r9;
string n_r1, n_r2, n_r3, n_r5, n_r6, n_r7;
long long int n_r4;
sendUInt32(serverSocket, R.size());
for (result::const_iterator c = R.begin(); c != R.end(); ++c) {
n_r = c[0].as<int>();
n_r1 = c[1].as<string>();
n_r2 = c[2].as<string>();
n_r3 = c[3].as<string>();
n_r4 = c[4].as<long long int>();
n_r5 = c[5].as<string>();
n_r6 = c[6].as<string>();
n_r7 = c[7].as<string>();
n_r8 = c[8].as<int>();
n_r9 = c[9].as<int>();
sendInt32(serverSocket, n_r);
sendString(serverSocket, n_r1);
sendString(serverSocket, n_r2);
sendString(serverSocket, n_r3);
sendInt64(serverSocket, n_r4);
sendString(serverSocket, n_r5);
sendString(serverSocket, n_r6);
sendString(serverSocket, n_r7);
sendInt32(serverSocket, n_r8);
sendInt32(serverSocket, n_r9);
}
client.cpp
void recvRaw(int socket, void *data, size_t size)
{
char *ptr = reinterpret_cast<char*>(data);
while (size > 0)
{
int numRecvd = recv(socket, ptr, size, 0);
if (numRecvd <= 0) throw ...;
ptr += numRecvd;
size -= numRecvd;
}
}
uint32_t recvUInt32(int socket)
{
uint32_t value;
recvRaw(socket, &value, sizeof(value));
return ntohl(value);
}
int32_t recvInt32(int socket)
{
int32_t value;
recvRaw(socket, &value, sizeof(value));
return ntohl(value);
}
int64_t recvInt64(int socket)
{
int32_t value;
recvRaw(socket, &value, sizeof(value));
return ntohll(value); // or whatever equivalent your environment provides
}
string recvString(int socket)
{
string str;
uint32_t size = recvUInt32(socket);
if (size > 0)
{
str.resize(size);
recvRaw(socket, str.data(), size);
}
return str;
}
...
int n_r, n_r8, n_r9;
string n_r1, n_r2, n_r3, n_r5, n_r6, n_r7;
long long int n_r4;
uint32_t count = recvUInt32(TCPClientSocket);
for(uint32_t i = 0; i < count; ++i)
{
n_r = recvInt32(TCPClientSocket);
n_r1 = recvString(TCPClientSocket);
n_r2 = recvString(TCPClientSocket);
n_r3 = recvString(TCPClientSocket);
n_r4 = recvInt64(TCPClientSocket);
n_r5 = recvString(TCPClientSocket);
n_r6 = recvString(TCPClientSocket);
n_r7 = recvString(TCPClientSocket);
n_r8 = recvInt32(TCPClientSocket);
n_r9 = recvInt32(TCPClientSocket);
cout << 't' << n_r << 't' << n_r1 << 't' << n_r2 << 't' << n_r3 << 't' << n_r4 << 't' << n_r5 << 't' << n_r6 << 't' << n_r7 << 't' << n_r8 << 't' << n_r9 << endl << endl;
}