简体   繁体   English

Indy TCP Server冻结,不知道为什么

[英]Indy TCP Server Freezes, no idea why

I have a Server and a client (Delphi). 我有一个服务器和一个客户端(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") 在测试时,客户端运行在四台不同的计算机上(每台计算机将打开和关闭客户端大约6次),服务器突然停止回复客户端(客户端显示消息,提示“连接已正常关闭”)

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? 因此,错误似乎出在ADOQuery打开连接以执行SQL时,为什么仅在执行30次后才引起异常?

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). 如果您的服务器代码未明确执行此操作,则通常意味着在服务器的事件处理程序之一中引发了未捕获的异常,这将导致服务器关闭套接字(如果该异常是在OnConnect事件之后和OnDisconnect之前引发的,事件,则在关闭套接字之前触发OnDisconnect )。 TIdTCPServer has an OnException event to report that condition. TIdTCPServer具有一个OnException事件来报告该情况。

TIdTCPClient closes the socket during destruction if it is still open. 如果销毁的话, TIdTCPClient关闭销毁插座。

Update : TIdTCPServer is a multi-threaded component. 更新TIdTCPServer是一个多线程组件。 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. ADO使用绑定到创建线程的线程的普通线程COM对象,除非使用CoMarshalInterThreadInterfaceInStream() + CoGetInterfaceAndReleaseStream()IGlobalInterfaceTable接口跨线程边界将其编组,否则ADO只能在该线程上下文中使用。

In this situation, you should either: 在这种情况下,您应该:

  1. give each client its own ADO connection and query objects. 为每个客户端提供自己的ADO连接和查询对象。 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. A.在OnConnect事件中创建它们,并将它们存储在TIdContext以在OnExecute事件中使用,然后在OnDisconnect事件中释放它们。 Or just create and free them in the OnExecute event on an as-needed basis. 或者只是根据需要在OnExecute事件中创建并释放它们。

    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. B.从TIdThreadWithTask派生一个新类,并覆盖其虚拟的BeforeExecute()AfterExecute()方法来创建和释放ADO对象,然后将TIdSchedulerOfThread...组件之一分配给TIdTCPServer.Scheduler属性并分配您的线程类到TIdSchedulerOfThread.ThreadClass属性。 Then, in the server events, you can use TMyThreadClass(TIdYarnOfThread(TIdContext.Yarn).Thread) to access the calling thread's ADO objects. 然后,在服务器事件中,可以使用TMyThreadClass(TIdYarnOfThread(TIdContext.Yarn).Thread)访问调用线程的ADO对象。

  2. Create a separate pool of ADO objects. 创建一个单独的ADO对象池。 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. 当客户端需要访问数据库时,让其将适当的ADO对象编组到调用线程的上下文中,然后在完成时将这些对象放回池中。

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. 无论哪种方式,由于ADO都是基于COM的,所以请不要忘记在OnConnectOnDisconnect事件或TIdThreadWithTask.BeforeExecute()中为需要访问ADO对象的每个客户端线程调用CoInitialize/Ex()CoUnintialize()TIdThreadWithTask.BeforeExecute()TIdThreadWithTask.AfterExecute()方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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