TServerSocket:如何在发送消息之前检查 ListView 上的特定客户端是否仍处于连接状态?
TServerSocket: How check if a specific client on ListView still is connected before send message?
我有一个 Timer
并想向 ListView
的每个客户端发送消息以确定 ping 时间等。然后我有以下代码:
procedure TMainForm.Timer1Timer(Sender: TObject);
var
i: Integer;
begin
try
for i := 0 to ListView1.Items.count - 1 do
begin
ListView1.Items.Item[i].SubItems.Objects[2] := TObject(GetTickCount);
ServerSocket1.Socket.Connections[i].SendText('ping' + #13#10);
end;
except
exit;
end;
end;
在发送之前,检查客户端是否真的已连接或类似情况可能更合适。怎么做这个?提前致谢。
无需检查连接。如果客户端实际上已断开连接,则当您的 OnTimer
处理程序被触发时,它不会再出现在服务器的 Connections[]
列表中。您应该将 OnClientDisconnect
处理程序分配给 TServerSocket
以从 TListView
.
中删除客户端
如果由于某种原因,客户端仍在 Connections[]
列表中(即,因为基础连接已丢失但 TServerSocket
尚未检测到),则套接字将简单地缓存所有传出数据,直到其出站缓冲区填满,然后它将开始为每次发送返回 WSAWOULDBLOCK
错误。最终,OS 将使死连接超时,TServerSocket
会将其从 Connections[]
列表中删除,触发 OnClientDisconnect
事件。
至少,在您显示的代码中,您应该将发送循环更新为 Close()
任何实际发送失败的套接字,从而触发 OnClientDisconnect
事件以删除该客户端来自 TListView
,例如:
procedure TMainForm.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
var
Item: TListItem;
begin
Item := ListView1.Items.Add;
Item.Data := Socket;
...
end;
procedure TMainForm.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
var
Item: TListItem;
begin
Item := ListView1.FindData(0, Socket, True, False);
if Item <> nil then
Item.Delete;
end;
procedure TMainForm.Timer1Timer(Sender: TObject);
const
s: AnsiString = 'ping' + #13#10;
var
Item: TListItem;
Socket: TCustomWinSocket;
p: PAnsiChar;
i, len, sent: Integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
begin
Item := ListView1.Items[i];
Item.SubItems.Objects[2] := TObject(GetTickCount);
Socket := TCustomWinSocket(Item.Data);
try
// SendText() does not handle partial sends, or Unicode strings...
//Socket.SendText('ping' + #13#10);
p := PAnsiChar(s);
len := Length(s);
repeat
sent := Socket.SendBuf(p^, len);
if sent = -1 then
being
if WSAGetLastError() <> WSAEWOULDBLOCK then
Break;
// TODO: stop trying after several attempts fail...
Continue;
end;
Inc(p, sent);
Dec(len, sent);
until len = 0;
if len = 0 then
Continue;
except
end;
Socket.Close;
end;
end;
我有一个 Timer
并想向 ListView
的每个客户端发送消息以确定 ping 时间等。然后我有以下代码:
procedure TMainForm.Timer1Timer(Sender: TObject);
var
i: Integer;
begin
try
for i := 0 to ListView1.Items.count - 1 do
begin
ListView1.Items.Item[i].SubItems.Objects[2] := TObject(GetTickCount);
ServerSocket1.Socket.Connections[i].SendText('ping' + #13#10);
end;
except
exit;
end;
end;
在发送之前,检查客户端是否真的已连接或类似情况可能更合适。怎么做这个?提前致谢。
无需检查连接。如果客户端实际上已断开连接,则当您的 OnTimer
处理程序被触发时,它不会再出现在服务器的 Connections[]
列表中。您应该将 OnClientDisconnect
处理程序分配给 TServerSocket
以从 TListView
.
如果由于某种原因,客户端仍在 Connections[]
列表中(即,因为基础连接已丢失但 TServerSocket
尚未检测到),则套接字将简单地缓存所有传出数据,直到其出站缓冲区填满,然后它将开始为每次发送返回 WSAWOULDBLOCK
错误。最终,OS 将使死连接超时,TServerSocket
会将其从 Connections[]
列表中删除,触发 OnClientDisconnect
事件。
至少,在您显示的代码中,您应该将发送循环更新为 Close()
任何实际发送失败的套接字,从而触发 OnClientDisconnect
事件以删除该客户端来自 TListView
,例如:
procedure TMainForm.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
var
Item: TListItem;
begin
Item := ListView1.Items.Add;
Item.Data := Socket;
...
end;
procedure TMainForm.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
var
Item: TListItem;
begin
Item := ListView1.FindData(0, Socket, True, False);
if Item <> nil then
Item.Delete;
end;
procedure TMainForm.Timer1Timer(Sender: TObject);
const
s: AnsiString = 'ping' + #13#10;
var
Item: TListItem;
Socket: TCustomWinSocket;
p: PAnsiChar;
i, len, sent: Integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
begin
Item := ListView1.Items[i];
Item.SubItems.Objects[2] := TObject(GetTickCount);
Socket := TCustomWinSocket(Item.Data);
try
// SendText() does not handle partial sends, or Unicode strings...
//Socket.SendText('ping' + #13#10);
p := PAnsiChar(s);
len := Length(s);
repeat
sent := Socket.SendBuf(p^, len);
if sent = -1 then
being
if WSAGetLastError() <> WSAEWOULDBLOCK then
Break;
// TODO: stop trying after several attempts fail...
Continue;
end;
Inc(p, sent);
Dec(len, sent);
until len = 0;
if len = 0 then
Continue;
except
end;
Socket.Close;
end;
end;