它正在发送额外的数据,因为您将Write(TStream) 的AWriteByteCount 参数设置为true。 00 00 00 20 是网络字节顺序的流大小。 msgSize 是 0x00000020,也就是 32。如果您不希望发送流大小,则需要将 AWriteByteCount 参数设置为 false:
Form1->IdTCPClient1->IOHandler->Write(sms, 0, false);
此外,您应该使用WriteBufferClose() 而不是WriteBufferFlush(),如果Write() 引发异常,请不要忘记调用WriteBufferCancel()。 WriteBufferClose() 将缓冲的数据发送到套接字,然后关闭缓冲区,因此不会缓冲后续写入。 WriteBufferFlush() 将缓冲的数据发送到socket,但不关闭缓冲区,因此后续的写入会被缓冲。
此外,您可以通过将TMemoryStream 替换为TIdMemoryBufferStream 来稍微简化开销,这样您就不必在内存中制作单独的消息数据副本:
TIdMemoryBufferStream *sms = new TIdMemoryBufferStream(msgData, msgSize);
try
{
Form1->IdTCPClient1->IOHandler->WriteBufferOpen();
try
{
Form1->IdTCPClient1->IOHandler->Write(sms, 0, true); // or false
Form1->IdTCPClient1->IOHandler->WriteBufferClose();
}
catch (const Exception &)
{
Form1->IdTCPClient1->IOHandler->WriteBufferCancel();
throw;
}
}
__finally
{
delete sms;
}
或者,使用 RAII 方法:
class BufferIOWriting
{
private:
TIdIOHandler *m_IO;
bool m_Finished;
public:
BufferIOWriting(TIdIOHandler *aIO) : m_IO(aIO), m_Finished(false)
{
IO->WriteBufferOpen();
}
~BufferIOWriting()
{
if (m_Finished)
m_IO->WriteBufferClose();
else
m_IO->WriteBufferCancel();
}
void Finished()
{
m_Finished = true;
}
};
{
std::auto_ptr<TIdMemoryBufferStream> sms(new TIdMemoryBufferStream(msgData, msgSize));
BufferIOWriting buffer(Form1->IdTCPClient1->IOHandler);
Form1->IdTCPClient1->IOHandler->Write(sms.get(), 0, true); // or false
buffer.Finished();
}
话虽如此,我建议完全摆脱写入缓冲:
TIdMemoryBufferStream *sms = new TIdMemoryBufferStream(msgData, msgSize);
try
{
Form1->IdTCPClient1->IOHandler->Write(sms, 0, true); // or false
}
__finally
{
delete sms;
}
或者:
{
std::auto_ptr<TIdMemoryBufferStream> sms(new TIdMemoryBufferStream(msgData, msgSize));
Form1->IdTCPClient1->IOHandler->Write(sms.get(), 0, true); // or false
}
当您需要进行多个相关的Write() 调用时,写缓冲很有用,这些调用应该在尽可能少的 TCP 帧中一起传输它们的数据(换句话说,让 Nagle 算法更好地完成它的工作)。例如,如果您需要 Write() 消息的各个字段。在进行单个 Write() 调用时,使用写缓冲没有多大意义,尤其是在如此小的尺寸下。让Write(TStream) 在内部为您处理自己的缓冲。