简体   繁体   中英

Indy TCP Server Freezes, no idea why

I have a Server and a client (Delphi).

The client gets login details and then connects to the server sends them to the server to be validated, the server receives the data validates it then returns whether the given data is correct.

If the data was correct the client continues to the next window where they enter some data into corresponding fields and then sends the data to the server, when the server receives the data it stores it and then replies to the client that it stored it successfully. When the client has been notified that the data was stored successfully it displays a message notifying the user and then terminates.

While testing this, with the client running on four different computers, (Each computer would have opened and closed the client about 6 times) the server suddenly stops replying to the clients (Clients display message saying "Connection closed gracefully")

This is the error the server is returning: 这是服务器返回的错误
So the error appears to be when ADOQuery opens the connection to execute the SQL, why would it cause a exception only after 30 executes?

Any Suggestions to what my problem is as I have no idea what it might be. Thanks for your help :)

If a client receives a "Connection closed gracefully" error, it means the server closed that client's connection on the server side. If your server code is not explicitly doing that, then it usually means an uncaught exception was raised in one of the server's event handlers, which would cause the server to close the socket (if the exception is raised after the OnConnect event and before the OnDisconnect event, OnDisconnect is triggered before the socket is closed). TIdTCPServer has an OnException event to report that condition.

TIdTCPClient closes the socket during destruction if it is still open.

Update : TIdTCPServer is a multi-threaded component. Each client connection runs in its own thread. ADO uses apartment-threaded COM objects that are tied to the thread that creates them, and can only be used within that thread context unless marshaled across thread boundaries using CoMarshalInterThreadInterfaceInStream() + CoGetInterfaceAndReleaseStream() , or the IGlobalInterfaceTable interface.

In this situation, you should either:

  1. give each client its own ADO connection and query objects. You could either:

    A. create them in the OnConnect event and store them within the TIdContext for use in the OnExecute event, and then free them in the OnDisconnect eventt. Or just create and free them in the OnExecute event on an as-needed basis.

    B. derive a new class from TIdThreadWithTask and override its virtual BeforeExecute() and AfterExecute() methods to create and free the ADO objects, and then assign one of the TIdSchedulerOfThread... components to the TIdTCPServer.Scheduler property and assign your thread class to the TIdSchedulerOfThread.ThreadClass property. Then, in the server events, you can use TMyThreadClass(TIdYarnOfThread(TIdContext.Yarn).Thread) to access the calling thread's ADO objects.

  2. Create a separate pool of ADO objects. When a client needs to access the database, have it marshal the appropriate ADO objects to the calling thread's context, and then put the objects back in the pool when finished.

Either way, since ADO is COM-based, don't forget to call CoInitialize/Ex() and CoUnintialize() for each client thread that needs to access ADO objects, either in the OnConnect and OnDisconnect events, or in the TIdThreadWithTask.BeforeExecute() and TIdThreadWithTask.AfterExecute() methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM