请问各位高手,你们是怎样在ServerSocket下维护多clientSocket客户端。我现在的办法是建一个class去维护,但觉得很麻烦。我想用serverSocket本身的connections来维护,不知怎作。怎样对指定客户端发信息。怎样把接爱的数据放到指定的地方。相互不干扰。

解决方案 »

  1.   

    clientsocket:array[1..50] of tcustomwinsocket;
    clientuser:array[1..50]   of string;
      

  2.   

    clientsocket:array[1..50] of tcustomwinsocket;
    clientuser:array[1..50]   of string;一个存客户端,一个存名字
      

  3.   

    我现在是这样作的:不过觉得订烦
    type
      TClientRecord=Record
        crHandle:THandle;           //客户句柄
        crSocket:TCustomWinSocket;  //客户socket
        crComputer:string;          //客户计算机名
        crIp:string;                //客户IP
        crUsed:boolean;             //此用户是否在线
        crSendData:array of string; //发送数据
        crDataCount:integer;        //
        crCount:integer;
        crUserID:string;            //用户ID
        crRights:string;            //用户权限
      end;type
      TSess=class(TObject)
      private
        MaxCount:integer;            //最大客户数量
      public
        LinkedCount:integer;         //在线客户数量
        Count:integer;               //曾经最大在线数量即最大的索引号
        Clients:array [0..MaxClient-1] of TClientRecord; //客户记录
        constructor create;
        function AddClient(Socket:TCustomWinSocket):boolean;
        procedure UpdateClient(index:integer;Socket:TCustomWinsocket);
        procedure DelClient(index:integer);
        function FindClient(var index:integer;crHandle:THandle):boolean;
        function FindUnUsed(var Index:Integer):Boolean;
      end;
      

  4.   

    TIdTCPServer creates a secondary listening thread that is independent from the main thread of the program. The listener thread listens for incoming requests from clients. For each client that it answers, it creates a new thread to specifically service that individual client connection. The appropriate events are then fired within the context of that thread.
      

  5.   

    原来尝试的用C++写过一个这种东西。关键是维护客户端连接的线程,每一个客户端连接到服务器都要新一个线程。如果你采用阻塞的Socket组件-Indy,他已经给你做好了。而且好像比自己写的稳定的多。
      

  6.   

    type 
    client_record=record 
    CHandle: integer; //客户端套接字句柄 
    CSocket:TCustomWinSocket; //客户端套接字 
    CName:string; //客户端计算机名称 
    CAddress:string; //客户端计算机IP地址 
    CUsed: boolean; //客户端联机标志 
    end; 
    利用这个记录类型数据保存客户端的信息,同时保存当前客户端的连接状态。其中,CHandle保存客户端套接字句柄,以便准确定位每个与服务器端保持连接的客户端;Csocket保存客户端套接字,通过它可以对客户端进行回复。Cused记录当前客户端是否与服务器端保持连接。 
    下面对组件ServerSocket和ClientSocket的属性设置简单说明。 
    ServerSocket的属性: 
    · Port,是通信的端口,必须设置。在本例中设置为1025; 
    · ServerTypt,服务器端读写信息类型,设置为stNonBlocking表示异步读写信息,本例中采用这种方式。 
    · ThreadCacheSize,客户端的最大连接数,就是服务器端最多允许多少客户端同时连接。本例采用默认值10。 
    其它属性采用默认设置即可。 
    ClientSocket的属性: 
    · Port,是通信的端口,必须与服务器端的设置相同。在本例中设置为1025; 
    · ClientType,客户端读写信息类型,应该与服务器端的设置相同,为stNonBlocking表示异步读写信息。 
    · Host,客户端要连接的服务器的IP地址。必须设置,当然也可以在代码中动态设置。 
    其它属性采用默认设置即可。 
    程序源代码: 
    · 服务器端源码(uServerMain.pas): 
    unit uServerMain; 
    interface 
    uses 
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
    ScktComp, ToolWin, ComCtrls, ExtCtrls, StdCtrls, Buttons; 
    const 
    CMax=10; //客户端最大连接数 
    type 
    client_record=record 
    CHandle: integer; //客户端套接字句柄 
    CSocket:TCustomWinSocket; //客户端套接字 
    CName:string; //客户端计算机名称 
    CAddress:string; //客户端计算机IP地址 
    CUsed: boolean; //客户端联机标志 
    end; 
    type 
    TfrmServerMain = class(TForm) 
    ServerSocket: TServerSocket; 
    ControlBar1: TControlBar; 
    ToolBar1: TToolBar; 
    tbConnect: TToolButton; 
    tbClose: TToolButton; 
    tbDisconnected: TToolButton; 
    Edit1: TEdit; 
    Memo1: TMemo; 
    StatusBar: TStatusBar; 
    procedure tbConnectClick(Sender: TObject); 
    procedure tbDisconnectedClick(Sender: TObject); 
    procedure ServerSocketClientRead(Sender: TObject; 
    Socket: TCustomWinSocket); 
    procedure ServerSocketListen(Sender: TObject; 
    Socket: TCustomWinSocket); 
    procedure ServerSocketClientConnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    procedure ServerSocketClientDisconnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    procedure tbCloseClick(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    procedure FormClose(Sender: TObject; var Action: TCloseAction); 
    procedure ServerSocketGetSocket(Sender: TObject; Socket: Integer; 
    var ClientSocket: TServerClientWinSocket); 
    procedure ServerSocketClientError(Sender: TObject; 
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; 
    var ErrorCode: Integer); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    session: array[0..CMax] of client_record; //客户端连接数组 
    Sessions: integer; //客户端连接数 
    end; 
    var 
    frmServerMain: TfrmServerMain; 
    implementation 
    {$R *.DFM} 
    //打开套接字连接,并使套接字进入监听状态 
    procedure TfrmServerMain.tbConnectClick(Sender: TObject); 
    begin 
    ServerSocket.Open ; 
    end; 
    //关闭套接字连接,不再监听客户端的请求 
    procedure TfrmServerMain.tbDisconnectedClick(Sender: TObject); 
    begin 
    ServerSocket.Close; 
    StatusBar.Panels[0].Text :='服务器套接字连接已经关闭,无法接受客户端的连接请求.'; 
    end; 
    //从客户端读取信息 
    procedure TfrmServerMain.ServerSocketClientRead(Sender: TObject; 
    Socket: TCustomWinSocket); 
    var 
    i:integer; 
    begin 
    //将从客户端读取的信息添加到Memo1中 
    Memo1.Lines.Add(Socket.ReceiveText); 
    for i:=0 to sessions do 
    begin 
    //取得匹配的客户端 
    if session[i].CHandle = Socket.SocketHandle then 
    begin 
    session[i].CSocket.SendText('回复客户端'+session[i].CAddress+' ==> '+Edit1.Text); 
    end; 
    end; 
    end; 
    //服务器端套接字进入监听状态,以便监听客户端的连接 
    procedure TfrmServerMain.ServerSocketListen(Sender: TObject; 
    Socket: TCustomWinSocket); 
    begin 
    StatusBar.Panels[0].Text :='等待客户端连接...'; 
    end; 
    //当客户端连接到服务器端以后 
    procedure TfrmServerMain.ServerSocketClientConnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    var 
    i,j:integer; 
    begin 
    j:=-1; 
    for i:=0 to sessions do 
    begin 
    //在原有的客户端连接数组中有中断的客户端连接 
    if not session[i].CUsed then 
    begin 
    session[i].CHandle := Socket.SocketHandle ;//客户端套接字句柄 
    session[i].CSocket := Socket; //客户端套接字 
    session[i].CName := Socket.RemoteHost ; //客户端计算机名称 
    session[i].CAddress := Socket.RemoteAddress ;//客户端计算机IP 
    session[i].CUsed := True; //连接数组当前位置已经占用 
    Break; 
    end; 
    j:=i; 
    end; 
    if j=sessions then 
    begin 
    inc(sessions); 
    session[j].CHandle := Socket.SocketHandle ; 
    session[j].CSocket := Socket; 
    session[j].CName := Socket.RemoteHost ; 
    session[j].CAddress := Socket.RemoteAddress ; 
    session[j].CUsed := True; 
    end; 
    StatusBar.Panels[0].Text := '客户端 '+Socket.RemoteHost + ' 已经连接'; 
    end; 
    //当客户端断开连接时 
    procedure TfrmServerMain.ServerSocketClientDisconnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    var 
    i:integer; 
    begin 
    for i:=0 to sessions do 
    begin 
    if session[i].CHandle =Socket.SocketHandle then 
    begin 
    session[i].CHandle :=0; 
    session[i].CUsed := False; 
    Break; 
    end; 
    end; 
    StatusBar.Panels[0].Text :='客户端 '+Socket.RemoteHost + ' 已经断开'; 
    end; 
    //关闭窗口 
    procedure TfrmServerMain.tbCloseClick(Sender: TObject); 
    begin 
    Close; 
    end; 
    procedure TfrmServerMain.FormCreate(Sender: TObject); 
    begin 
    sessions := 0; 
    end; 
    procedure TfrmServerMain.FormClose(Sender: TObject; 
    var Action: TCloseAction); 
    begin 
    ServerSocket.Close ; 
    end; 
    //当客户端正在与服务器端连接时 
    procedure TfrmServerMain.ServerSocketGetSocket(Sender: TObject; 
    Socket: Integer; var ClientSocket: TServerClientWinSocket); 
    begin 
    StatusBar.Panels[0].Text :='客户端正在连接...'; 
    end; 
    //客户端发生错误 
    procedure TfrmServerMain.ServerSocketClientError(Sender: TObject; 
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; 
    var ErrorCode: Integer); 
    begin 
    StatusBar.Panels[0].Text :='客户端'+Socket.RemoteHost +'发生错误!'; 
    ErrorCode := 0; 
    end; 
    end. 
     
      

  7.   

    · 客户端源码(uClientMain.pas): 
    unit uClientMain; 
    interface 
    uses 
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
    ScktComp, ComCtrls, ToolWin, ExtCtrls, StdCtrls, Buttons; 
    const 
    SocketHost = '172.16.1.6'; //服务器端地址 
    type 
    TfrmClientMain = class(TForm) 
    ControlBar1: TControlBar; 
    ToolBar1: TToolBar; 
    tbConnected: TToolButton; 
    tbSend: TToolButton; 
    tbClose: TToolButton; 
    tbDisconnected: TToolButton; 
    ClientSocket: TClientSocket; 
    Edit1: TEdit; 
    Memo1: TMemo; 
    StatusBar: TStatusBar; 
    btnSend: TBitBtn; 
    procedure tbConnectedClick(Sender: TObject); 
    procedure tbDisconnectedClick(Sender: TObject); 
    procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket); 
    procedure tbSendClick(Sender: TObject); 
    procedure tbCloseClick(Sender: TObject); 
    procedure FormShow(Sender: TObject); 
    procedure ClientSocketConnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    procedure ClientSocketConnecting(Sender: TObject; 
    Socket: TCustomWinSocket); 
    procedure ClientSocketDisconnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    procedure FormClose(Sender: TObject; var Action: TCloseAction); 
    procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket; 
    ErrorEvent: TErrorEvent; var ErrorCode: Integer); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 
    var 
    frmClientMain: TfrmClientMain; 
    implementation 
    {$R *.DFM} 
    //打开套接字连接 
    procedure TfrmClientMain.tbConnectedClick(Sender: TObject); 
    begin 
    ClientSocket.Open ; 
    end; 
    //关闭套接字连接 
    procedure TfrmClientMain.tbDisconnectedClick(Sender: TObject); 
    begin 
    ClientSocket.Close; 
    end; 
    //接受服务器端的回复 
    procedure TfrmClientMain.ClientSocketRead(Sender: TObject; 
    Socket: TCustomWinSocket); 
    begin 
    Memo1.Lines.Add(Socket.ReceiveText); 
    end; 
    //发送信息到服务器端 
    procedure TfrmClientMain.tbSendClick(Sender: TObject); 
    begin 
    ClientSocket.Socket.SendText(Edit1.Text); 
    end; 
    procedure TfrmClientMain.tbCloseClick(Sender: TObject); 
    begin 
    Close; 
    end; 
    //设置要连接的服务器端地址 
    procedure TfrmClientMain.FormShow(Sender: TObject); 
    begin 
    ClientSocket.Host := SocketHost; 
    end; 
    //已经连接到服务器端 
    procedure TfrmClientMain.ClientSocketConnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    begin 
    tbSend.Enabled := True; 
    tbDisconnected.Enabled :=True; 
    btnSend.Enabled := True; 
    StatusBar.Panels[0].Text := '已经连接到 '+ Socket.RemoteHost ; 
    end; 
    //正在连接到服务器端 
    procedure TfrmClientMain.ClientSocketConnecting(Sender: TObject; 
    Socket: TCustomWinSocket); 
    begin 
    StatusBar.Panels[0].Text := '正在连接到服务器... ' ; 
    end; 
    //当断开与服务器端的连接时发生 
    procedure TfrmClientMain.ClientSocketDisconnect(Sender: TObject; 
    Socket: TCustomWinSocket); 
    begin 
    tbSend.Enabled := False; 
    btnSend.Enabled := False; 
    tbDisconnected.Enabled := False; 
    StatusBar.Panels[0].Text := '已经断开与 '+ Socket.RemoteHost +' 的连接'; 
    end; 
    procedure TfrmClientMain.FormClose(Sender: TObject; 
    var Action: TCloseAction); 
    begin 
    ClientSocket.Close ; 
    end; 
    //当与服务器端的连接发生错误时 
    procedure TfrmClientMain.ClientSocketError(Sender: TObject; 
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; 
    var ErrorCode: Integer); 
    begin 
    StatusBar.Panels[0].Text := '与服务器端的连接发生错误'; 
    ErrorCode := 0; 
    end; 
    end. 
    小结 
    上述方法是比较简单的实现方法,同时也是相对较容易理解的方法。通过这个方法,笔者成功实现了局域网内多个客户端与服务器端进行Socket通信的功能,同时可以保证一个客户端的连接、通信或是断开都不影响其它客户端的正常通信。
      

  8.   

    indy 不错的
    完全可以完成你的要求
    它的Athread估计比自己写的稳定点
      

  9.   

    哪里有关于indy的文章,没用过indy。
      

  10.   

    可以参考下Delphi自带的例子 Demos\Internet\Chat
      

  11.   

    type
      TSimpleClient = class(TObject)(保存一个用户信息)
        FCHandle: integer;         
        FListLink: Integer;
        FCSocket:TCustomWinSocket;    
        FCAddress:string;
        FCUsed: boolean; 
      end          
    Clients: TList;(在将TSimpleClient加到Clients,存储了所有用户信息)