我正在写一个QTcpServer
. 我用作telnet.exe
测试的客户端。在新的客户端连接上,我的服务器向Hi!
显示的客户端发送一条消息 - 到目前为止一切都很好。
但是当我在telnet.exe
窗口中输入内容时,每个字符readyRead()
都会发出a 。我只希望它在之后发送!有什么问题?这是Windows的本质吗?因为我在我的 linux 机器上使用过,它只在 之后发送字符串,正如预期的那样。\r\n
telnet.exe
telnet
\r\n
我正在写一个QTcpServer
. 我用作telnet.exe
测试的客户端。在新的客户端连接上,我的服务器向Hi!
显示的客户端发送一条消息 - 到目前为止一切都很好。
但是当我在telnet.exe
窗口中输入内容时,每个字符readyRead()
都会发出a 。我只希望它在之后发送!有什么问题?这是Windows的本质吗?因为我在我的 linux 机器上使用过,它只在 之后发送字符串,正如预期的那样。\r\n
telnet.exe
telnet
\r\n
不幸的是,这就是 Windows telnet.exe 客户端的工作方式,没有办法改变它。
在处理 TCP 流时,您不能依赖这样的客户端特定行为。TCP 不保证消息边界,但它确实保证,从您的角度来看,数据按照客户端写入的相同顺序传递。在设计协议时,您必须考虑到这一点。
您需要缓冲传入数据并在应用程序协议级别进行处理。常见的解决方案包括定义消息终止序列(以及如果该序列可以出现在正常消息中,则转义该序列的机制) - 例如,\r\n 可能是这种情况下的终止序列 - 或者您可以打包发送的数据前缀它带有后续消息长度,或者您可以使用专用的消息传递库(例如ZeroMQ或ActiveMQ - 但不幸的是,您不能使用 Qt 的网络)等。
不要键入您的消息,而是按CTRL+ ],然后键入send YOURMESSAGE\r\n
是的,带有 CR LF 的 windows 和 linux 之间存在一些差异,这是“正常的”。
一种很好的方法是利用缓冲区,然后等待您的数据准备好或超时。例如,您的分隔符标记可以是“\r”,如果您在删除它后得到一个“\n”。
这是一个期望来自自定义协议的令牌的示例:
int Connection::readDataIntoBuffer(int maxSize)
{
if (maxSize > MaxBufferSize)
return 0;
int numBytesBeforeRead = buffer.size();
if (numBytesBeforeRead == MaxBufferSize) {
abort();
return 0;
}
while (bytesAvailable() > 0 && buffer.size() < maxSize) {
buffer.append(read(1));
if (buffer.endsWith(SeparatorToken))
break;
}
return buffer.size() - numBytesBeforeRead;
}
请参阅http://doc.qt.nokia.com/stable/network-network-chat-connection-cpp.html
根据您需要的另一个建议是尝试坚持一些标准协议。像这样,您可以使用不同类型的客户端进行测试。
如果您想坚持您的自定义协议,我建议您编写自己的客户端并编写适当的测试用例以与您的服务器协作。Qt 让它变得简单快捷;) 看看网络示例。
编辑:
你可能会考虑readline()
而不是read()
你的QTcpSocket
which is an QIODevice
. 它等待换行符而不是 read() (请参阅下面的文档摘录)。但是,这可以减少对何时结束线路的控制:
qint64 QIODevice::readLine ( char * data, qint64 maxSize )
从文档:
读取数据直到满足以下任一条件:
- 读取第一个 '\n' 字符。
- maxSize - 读取 1 个字节。
- 检测到设备数据的结束。
Qt 的秘密成分是异步信号驱动设计。有关一些想法,请参阅文章线程、事件和 QObjects中的网络/状态机部分。