【发布时间】:2015-06-01 12:45:14
【问题描述】:
我正在我的 deplhi 项目中实现实时聊天,它通过向服务器发出 GET 请求来接收新消息。如果没有新消息出现,服务器本身会在 20 秒后关闭连接。上面描述的代码位于一个单独的线程中(它是在访问聊天“页面”时创建的),因此它不会冻结 GUI。当我从聊天转到非聊天页面时,我在thread_chat 之外调用此代码以使线程退出:
if thread_chat <> nil then
begin
thread_chat.Terminate;
thread_chat := nil;
end;
但是,由于我的服务器超时为 20 秒,因此线程实际上仅在收到响应时才关闭(是的,这听起来合乎逻辑,因为我的线程循环是 while not Terminated do)。所以我正在寻找的是在请求中间关闭 HTTP 连接。
尝试 #1
最初我通过称呼它来查看TerminateThread
TerminateThread(thread_chat.Handle, 0)
这工作正常,直到我第二次尝试杀死线程 - 我的应用程序完全冻结。于是我去了
尝试 #2
我创建了一个全局变量URL_HTTP: TIdHTTP,并通过此函数接收服务器页面内容:
function get_URL_Content(const Url: string): string;
var URL_stream: TStringStream;
begin
URL_HTTP := TIdHTTP.Create(nil);
URL_stream := TStringStream.Create(Result);
URL_HTTP.Get(Url, URL_stream);
if URL_HTTP <> nil then
try
URL_stream.Position := 0;
Result := URL_stream.ReadString(URL_stream.Size);
finally
FreeAndNil(URL_HTTP);
FreeAndNil(URL_stream);
end;
end;
当我在 thread_chat 之外调用此代码时
if thread_chat <> nil then
begin
URL_HTTP.Disconnect;
thread_chat.Terminate;
end;
我得到EidClosedSocket 异常(在写这篇文章时经过一些测试,我得到EAccessViolation 错误)。
我的想法已经用完了。如何在服务器响应之前关闭 HTTP 请求?
procedure thread_chat.Execute; //overrided
begin
while not Terminated do
if check_messages then //sends request to the server, processes response, true if new message(s) exist
show_messages;
end;
【问题讨论】:
-
您的第二种方法是尝试访问一个
TIdHTTP对象,该对象是get_URL_Content()的本地对象,并且由get_URL_Content()免费提供,因此您有一个竞争条件。您需要将TIdHTTP对象作为数据成员移动到您的线程类中,然后您可以在终止线程时断开它。 -
话虽如此,如果您不发送 HTTP 请求,您的线程如何阻塞?或者您是否发送了一个 HTTP 请求以保持连接打开并接收服务器生成的推送消息? HTTP 通常使用命令/响应模型,因此您的线程阻塞 20 秒以等待来自服务器的响应在推送模型之外没有多大意义(
TIdHTTP无论如何都不是为这种模型设计的)。请显示您遇到问题的实际线程代码。 -
@RemyLebeau 请求的服务器端是长轮询的,因此如果有新消息到达,请求将立即关闭,否则 - 服务器将仅在 20 秒后回复。我添加了我的线程代码
-
那么,如果服务器上没有消息等待,发送到服务器的请求会在20秒内没有收到响应?如果是这样,那么服务器设计不正确,需要修复。反应需要及时。如果没有消息等待,服务器应立即发送响应以准确说明客户端不会被阻塞。
-
@RemyLebeau 只是为了清除,20 秒后服务器响应
No new messages.。无论如何,我在网站的聊天中使用这种方法,所以我不太愿意改变时间
标签: multithreading delphi delphi-7 idhttp