开发者

QT QTcpServer telnet taking characters \r\n

开发者 https://www.devze.com 2023-02-22 02:19 出处:网络
I\'m writing a QTcpServer. I used telnet.exe as a client for testing. Upon a new client connection my server sends a Hi! message to the client which is displayed - all is well and fine so far.

I'm writing a QTcpServer. I used telnet.exe as a client for testing. Upon a new client connection my server sends a Hi! message to the client which is displayed - all is well and fine so far.

But when I type something in the telnet.exe window, a readyRead() is emitted for each character. I only want it to be sent after \r\n! What's the problem? Is it the nature of telnet.exe in Windows? Cause开发者_运维百科 I've used telnet on my linux box and it only sends the string after \r\n, as expected.


Unfortunately, that's how the Windows telnet.exe client works and there's no way to change that.

You must not rely on client-specific behavior like this when handling TCP streams. TCP does not guarantee message boundaries, but it does guarantee that, from your point of view, the data is delivered int he same order it was written by the client. You must take this into account when designing your protocol.

You'll need to buffer incoming data and handle this at the application protocol level. Common solutions include defining a message terminator sequence (and a mechanism for escaping that sequence if it can appear inside the normal messages) - for example, \r\n could be the terminator sequence in this scenario -, or you can packetize sent data prefixing it with the follow-up message length, or you can use dedicated messaging libraries (such as ZeroMQ or ActiveMQ - but then you can't use Qt's networking, unfortunately), etc.


Instead of typing your message, press CTRL + ], and then type send YOURMESSAGE\r\n


Yes, there are some differences between windows and linux with CR LF, it's "normal".

One approach that works nice is to make use of buffer and then wait for your data to be ready or timeout. For exmaple your seperator token can be “\r” and if you get an “\n” after just drop it.

Here is an example expecting a token from a custom protocol:

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;
 }

See http://doc.qt.nokia.com/stable/network-network-chat-connection-cpp.html

Depending on what you need another suggestion is to try an stick to some standard protocol. Like this you can test with different type of clients.

If you want to stick to your custom protocol I suggest you write your own client and write proper test cases to collaborate with your server. Qt makes it easy and fast ;) Take a look at the network examples.

Edit:

You might consider readline() instead of read() on your QTcpSocket which is an QIODevice. It waits for a newline instead of read() (see the doc excerpt below). However this gives less control over when to end your line:

qint64 QIODevice::readLine ( char * data, qint64 maxSize )

From the doc:

Data is read until either of the following conditions are met:

  • The first '\n' character is read.
  • maxSize - 1 bytes are read.
  • The end of the device data is detected.

The secret ingredient in Qt is asynchronous signal driven-design. See the section Networking / State Machines section in the article Threads, Events and QObjects for some ideas.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号