从 C/C++ 中的 TCP 套接字读取的正确方法是什么?
这是我的代码:
// Not all headers are relevant to the code snippet.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
char *buffer;
stringstream readStream;
bool readData = true;
while (readData)
{
cout << "Receiving chunk... ";
// Read a bit at a time, eventually "end" string will be received.
bzero(buffer, BUFFER_SIZE);
int readResult = read(socketFileDescriptor, buffer, BUFFER_SIZE);
if (readResult < 0)
{
THROW_VIMRID_EX("Could not read from socket.");
}
// Concatenate the received data to the existing data.
readStream << buffer;
// Continue reading while end is not found.
readData = readStream.str().find("end;") == string::npos;
cout << "Done (length: " << readStream.str().length() << ")" << endl;
}
正如您所知,它有点 C 和 C++.BUFFER_SIZE 是 256 - 我应该增加大小吗?如果是这样,该怎么办?重要吗?
It's a little bit of C and C++ as you can tell. The BUFFER_SIZE is 256 - should I just increase the size? If so, what to? Does it matter?
我知道如果由于任何原因没有收到end",这将是一个无限循环,这很糟糕 - 所以如果你能提出更好的方法,也请这样做.
I know that if "end" is not received for what ever reason, this will be an endless loop, which is bad - so if you could suggest a better way, please also do so.
推荐答案
在不了解您的完整应用程序的情况下,很难说出解决问题的最佳方法是什么,但一种常见的技术是使用以固定长度字段,表示消息其余部分的长度.
Without knowing your full application it is hard to say what the best way to approach the problem is, but a common technique is to use a header which starts with a fixed length field, which denotes the length of the rest of your message.
假设您的标头仅由一个 4 字节的整数组成,它表示消息其余部分的长度.然后只需执行以下操作.
Assume that your header consist only of a 4 byte integer which denotes the length of the rest of your message. Then simply do the following.
// This assumes buffer is at least x bytes long,
// and that the socket is blocking.
void ReadXBytes(int socket, unsigned int x, void* buffer)
{
int bytesRead = 0;
int result;
while (bytesRead < x)
{
result = read(socket, buffer + bytesRead, x - bytesRead);
if (result < 1 )
{
// Throw your error.
}
bytesRead += result;
}
}
然后在代码中
unsigned int length = 0;
char* buffer = 0;
// we assume that sizeof(length) will return 4 here.
ReadXBytes(socketFileDescriptor, sizeof(length), (void*)(&length));
buffer = new char[length];
ReadXBytes(socketFileDescriptor, length, (void*)buffer);
// Then process the data as needed.
delete [] buffer;
这里有几个假设:
- 发送方和接收方的整数大小相同.
- 发送方和接收方的字节序相同.
- 您可以控制双方的协议
- 发送消息时,您可以预先计算长度.
因为想要明确知道您通过网络发送的整数的大小是很常见的,所以在头文件中定义它们并明确使用它们,例如:
Since it is common to want to explicitly know the size of the integer you are sending across the network define them in a header file and use them explicitly such as:
// These typedefs will vary across different platforms
// such as linux, win32, OS/X etc, but the idea
// is that a Int8 is always 8 bits, and a UInt32 is always
// 32 bits regardless of the platform you are on.
// These vary from compiler to compiler, so you have to
// look them up in the compiler documentation.
typedef char Int8;
typedef short int Int16;
typedef int Int32;
typedef unsigned char UInt8;
typedef unsigned short int UInt16;
typedef unsigned int UInt32;
这会将上面的内容更改为:
This would change the above to:
UInt32 length = 0;
char* buffer = 0;
ReadXBytes(socketFileDescriptor, sizeof(length), (void*)(&length));
buffer = new char[length];
ReadXBytes(socketFileDescriptor, length, (void*)buffer);
// process
delete [] buffer;
我希望这会有所帮助.
相关文章