我正在通过TCP / IP发送消息,我需要在char数组中为消息长度添加前缀,然后发送它。我该怎么做?
另外,请您提供一个如何在另一端提取它的示例。如果可能的话,请解释一下。
我正在使用C ++和Winsock。
修改
string writeBuffer = "Hello";
unsigned __int32 length = htonl(writeBuffer.length());
它没有返回正确的长度而是非常大的数字。
对于接收部分,如果我使用ntohl(),那么我也得到一个大数而不是正确的长度?为什么会这样?我收到这样的
bool Server::Receive(unsigned int socketIndex)
{
// Read data from the socket
if (receivingLength)
{
bytesReceived = recv(socketArray[socketIndex - WSA_WAIT_EVENT_0],
((char*)&messageLength) + bytesReceived, MESSAGE_LENGTH_SIZE - bytesReceived, 0);
if (bytesReceived == SOCKET_ERROR)
{
return false;
}
if (bytesReceived == MESSAGE_LENGTH_SIZE)
{
// If uncomment the following line,
// I won't get the correct length, but a large number
//messageLength = ntohl(messageLength);
receivingLength = false;
bytesReceived = 0;
bytesLeft = messageLength;
}
}
else
{
if (bytesLeft > BUFFER_SIZE)
{
return false;
}
bytesReceived = recv(socketArray[socketIndex - WSA_WAIT_EVENT_0],
&receiveBuffer[bytesReceived], bytesLeft, 0);
if (bytesReceived == SOCKET_ERROR)
{
return false;
}
if (bytesReceived == messageLength)
{
// we have received full message
messageReceived = true;
receiveBuffer[bytesReceived] = '\0';
// wait for next message
receivingLength = true;
}
bytesLeft -= bytesReceived;
}
return true;
}
答案 0 :(得分:6)
在TCP流上发送长度字段时,您需要确定两件事:
我建议使用4个字节的长度和网络字节顺序(即big-endian)。对于网络字节顺序,宏htonl和ntohl将在主机(本机)字节顺序(在您的情况下为little-endian)和网络字节顺序之间进行转换。
要发送数据,片段应如下所示:
size_t length = strlen(data);
uint32_t nlength = htonl(length);
send(sock, &nlength, 4, 0);
send(sock, data, length, 0);
在接收方,首先提取长度,然后提取数据:
uint32_t length, nlength;
recv(sock, &nlength, 4, 0);
length = ntohl(nlength);
data = malloc(length+1);
recv(sock, data, length, 0);
data[length] = 0;
缺少此代码的是错误处理:每个发送和接收调用都可能失败; recvs可能收到的数据少于预期。但这应该会给你一个想法。
编辑:要处理recv返回的数据太少的情况,请在循环中运行它,并保留到目前为止所读内容的计数,例如。
int length_bytes = 0;
while(length_bytes < 4){
int read = recv(sock, ((char*)&nLength)+length_bytes, 4-length_bytes, 0);
if (read == -1) some_error_occurred_check_errno();
length_bytes += read;
}
答案 1 :(得分:1)
伪代码(省略错误处理,小心):
发件人:
u_long converted = htonl( messageLength ); // convert from local byte order to network byte order
send( socket, (char*)&converted, sizeof( converted ), 0 );
接收器:
u_long messageLength;
recv( socket, (char*)&messageLength, sizeof( messageLength ), 0 );
messageLength = ntohl( messageLength ); convert from network byte order to local byte order
答案 2 :(得分:0)
我不确定这是不是你要问的,但是我会把它作为一个固定长度的字符串发送(比方说4个字符,实际长度由你决定)。换句话说,如果数据长度为164,则发送字符串“0164”。这可以解决另一端的字节顺序问题,并且易于读取和调试。
要生成此类字符串,您可以使用字符串流:
#include <sstream>
#include <iomanip>
std::string MakeLenStr( int n ) {
std::ostringstream os;
os << std::setw(4) << std::setfill('0') << n;
return os.str();
}
发送:
std::string s = MakeLenStr( len );
send( sock, s.c_str(), 4 );
在另一端阅读,例如:
char a[5] = {0};
recv( sock, a, 4 );
int n = atoi( a );