These are chat archives for IndySockets/Indy
What is the correct way of shutting IdTCPServer down while it has clients connected to it? If I use this code:
IdTCPServer1.Active := False;
the application simply hangs.
try with AContext.Connection.IOHandler do begin CheckForDataOnSource(10); if not InputBufferIsEmpty then begin RxBufStr := InputBuffer.ExtractToString(-1, IndyTextEncoding_UTF8); Log(RxBufStr); AContext.Binding.SendTo(AContext.Binding.PeerIP, 7, RxBufStr, Id_IPv4); IdBuffer.Extract() end; end; finally end;
TIdBuffer.ExtractString(), especially with a text encoding involved. You are reading arbitrary bytes and assuming they constitute a complete sequence of characters, which is not guaranteed, so the bytes may not decode to a string properly. And, you shouldn't be calling
Binding.SendTo()directly at all (and besides, using
sendto()on a TCP/IP socket is meaningless anyway, the destination parameters are ignored so it acts the same as
send()). This kind of code is a good way to bypass TIdTCPServer's ability to auto-stop its client threads. It expects an exception to be raised when the socket is closed, but you are not allowing it to raise anything. The correct thing to do would be to use
TIdIOHandler.ReadBytes()instead, letting it block until new bytes arrive and raise an exception if the client disconnects or the server is being shutting down. And use
var RxBufStr: string; begin with AContext.Connection.IOHandler do begin CheckForDataOnSource(10); CheckForDisconnect; // <-- add this if not InputBufferIsEmpty then begin RxBufStr := InputBufferAsString(IndyTextEncoding_8Bit); // <-- don't assume any encoding Log(RxBufStr); Write(RxBufStr, IndyTextEncoding_8Bit); // <-- use TIdIOHandler.Write() instead end; end; end;
var RxBuf: TIdBytes; begin with AContext.Connection.IOHandler do begin ReadBytes(RxBuf, -1); Log(RxBuf); Write(RxBuf); end; end;
TIdTCPServer. For logging, you can assign a
TIdLogEvent, etc) to the
AContext.Connection.IOHandler.Interceptproperty, such as in the
TIdHTTPmore chances to continue authentication attempts. Please don't assume what you think is happening, debug and find out exactly what is really happening.
TIdTCPServeris to use blocking I/O that follows a defined protocol, raising exceptions on errors/disconnects/shutdowns, and let the server handle the exceptions. If you skip that logic, you become responsible for handling certain things manually, like shutdown. For instance, you could set a variable before setting
Active=False(or, just look at
Activeitself, since it is toggled to false before thread shutdowns occur), and then have
OnExecutelook at that variable, and if set then call
AContext.Connection.Disconnect, or raise your own exception, before exiting the event.
Log()itself is deadlocking, such as if it tries to synchronize with the main UI thread while the main UI thread is blocked waiting for the server to finish shutdown. Do not synchronize with the thread that is shutting down the server, that is a guaranteed deadlock. Either skip the synched operation during shutdown, or use a separate worker thread to shutdown the server so syncs can still be processed.
charand your code is not accounting for that. You can't use UTF-8 unless you ensure complete byte sequences for multi-byte characters, but your original code was not doing that. What kind of protocol is your server implementing? If the text is line-based, for instance, then you could just use
TIdIOHandler.ReadLn(), in which case using UTF-8 would be OK. But if you use
InputBufferAsStringthen all guarantees about the completeness of multi-byte sequences go out the window