Search code examples
indy

How To Deal With MaxLineLengthExceeded With Indy TIdTCPClient


I'm new to indy, using whatever version comes with CBuilder XE4. Here's very simple code that works fine until what I'm reading exceeds the 16K limit....

String Ttcp_mgr::send(String data)
{
  tcpClient->Socket->WriteLn(data); 
  return tcpClient->Socket->ReadLn();
}

The server is not using indy, there is no length header, going both ways is json terminated by \r\n. Blocking reads are fine, there's nothing for my app to do until it get's it's response, and it will be coming very quickly anyway. But the amount of data that is returned could be a few bytes or 100K, in a few cases. Generally the length will be < 500 bytes.

I've looked at IOHandler but I have no idea how to apply it to what I'm doing, not even sure it's what I need. As you can probably tell I'm not using the component on a form which probably makes no difference.


Solution

  • TIdIOHandler::ReadLn() has an optional AMaxLineLength input parameter. If you do not specify a value for it, the TIdIOHandler::MaxLineLength property is used, which is set to 16K by default. The TIdIOHandler::MaxLineAction property specifies what happens if ReadLn() actually reaches the max line length.

    If MaxLineAction is maException (the default), an EIdReadLnMaxLineLengthExceeded exception is raised.

    If MaxLineAction is maSplit, the TIdIOHandler::ReadLnSplit property is set to true and ReadLn() returns what it can. You would have to call ReadLn() again to read more data for the current line. This can end up chopping the data incorrectly if it is using a multi-byte encoding for non-ASCII characters, like UTF-8 (which is JSON's default encoding), so I do not recommend this approach.

    In your case, you should either:

    1. set the TIdIOHandler::MaxLineLength property to MaxInt:

      // TIdTCPClient::OnConnected event handler...
      void __fastcall Ttcp_mgr::tcpCllientConnected(TObject *Sender)
      {
          tcpClient->IOHandler->MaxLineLength = MaxInt;
      }
      
    2. pass MaxInt as a parameter to TIdIOHandler::ReadLn().

      String Ttcp_mgr::send(String data)
      {
          tcpClient->Socket->WriteLn(data); 
          return tcpClient->Socket->ReadLn(EOL, IdTimeoutDefault, MaxInt);
      }