1. 程式人生 > 其它 >Delphi TServerSocket 傳送訊息之前檢查客戶端是否仍處於連線狀態

Delphi TServerSocket 傳送訊息之前檢查客戶端是否仍處於連線狀態

TServerSocket:如何在傳送訊息之前檢查ListView上的特定客戶端是否仍處於連線狀態?

無需檢查連線。如果客戶端實際上已斷開連線,則在觸發處理程式Connections[]時,該客戶端將不再位於伺服器列表中OnTimer。您應該為OnClientDisconnect分配了處理程式,以TServerSocket從中刪除客戶端TListView。

如果由於某種原因,客戶端仍在Connections[]列表中(即,由於基礎連線已丟失但TServerSocket尚未檢測到),則套接字將僅快取所有傳出資料,直到其出站緩衝區填滿為止,然後將開始WSAWOULDBLOCK為每個傳送返回錯誤。最終,作業系統將使死連線超時並TServerSocket從Connections[]列表中將其刪除,從而觸發OnClientDisconnect事件。

至少,在顯示的程式碼中,應將send迴圈更新為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;