C/S架构下,如何判断帐号已经登陆,如果该帐号已经登陆,那么将不允许其他机器通过该帐号登陆,请问各位如何解决该问题?用Com吗?
多谢各位了!

解决方案 »

  1.   

    to: lovendII(戒情人) 
    谢谢你的回答,这样解决的可行性是有的,但是是否便于管理呢,拓展性是否高呢?如果我想查看当前的登陆帐号数量呢?
      

  2.   

    这个做成三层或有一个检测端就好了
    因为可能会有客户端异常退出的情况,那样异常退出就不能再次登录了我的思路是做一个检测程序,定时检测客户程序是否正常运行(这个用socket就可以做到),对于异常退出的客户端删除他的登录信息,这样就解决了异常退出的情况
      

  3.   

    >>如果该帐号已经登陆,那么将不允许其他机器通过该帐号登陆有一些解决方法,取决于你的用户数,如果是几十个的,是一回事,
    如果是上万的,可能就有不同的做法
      

  4.   

    to->回复人: fishmans(金脚指) 
      异常退出时应该怎样处理?socket又怎样用呢?我还没用过这方面的东西,希望能得到你的解答,谢谢!!
      

  5.   

    socket到底怎么用啊,针对该问题,各位大侠可否提供些代码引路啊!
      

  6.   

    to :aiirii(ari-淘金坑) ( ) 
    用户数量:两位数
      

  7.   

    不好意思除了趟差,好了现在把我的解决方案帖上:
    当然如果几个服务器有共享数据库最好,那实现起来容易许多,相信如果楼主需要这样的代码的话可能早有人帖了,好现在我做了一个在没有共享结构的情况下实现联合认证的代码,请楼主参考同一问题你所开的另一帖我所阐述的解决方案理解以下代码:
    (*
      本单元主要负责了在无共享数据库的环境下进行用户信息联合认证,提供一系列函数供参考
    *)
    unit CheckUserUnit;interface
    uses Windows,Messages,SysUtils,Classes,Contnrs,IdTCPConnection, IdTCPClient,
          IdBaseComponent, IdComponent, IdTCPServer;type
      //服务器信息结构
      TServerInfo=record
        IP:String;
        Port:Integer;
      end;
      //用户信息结构
      TUserInfo=record
        UserID:String[120];
        Password:String[32];
        CheckStr:String[16];
      end;
      TPUserInfo=^TUserInfo;
    var
      UserList:TList;
      UserCS:TRTLCriticalSection;
    //注册需要关联的服务器,用于客户信息的共享
    procedure ConfigServers(Servers:Array of TServerInfo);
    //开始服务器之间的关联,用于客户信息的分布式管理
    procedure BeginServerLink;
    //退出服务器的关联
    procedure EndServerLink;
    //检测该用户是否已在某个服务器注册
    function NetCheckUser(UserID,Password:String;var CheckStr:String):Boolean;
    //检测该用户是否已在本服务器注册
    function CheckUser(UserID,Password:String;var CheckStr:String):Boolean;
    //在本本服务器注册用户
    procedure RegUser(UserID,Password:String;var CheckStr:String);
    //
    procedure OpenCheckServer(Port:Integer);
    implementation
    type
      TCheckTCPServer=class(TObject)
      private
        TCPServer:TIdTCPServer;
        FActive: Boolean;
        FPort: Integer;
        procedure Execute(AThread: TIdPeerThread);
        procedure SetActive(const Value: Boolean);
        procedure SetPort(const Value: Integer);
      public
        constructor Create;
        destructor Destory;
        property Port:Integer read FPort write SetPort;
        property Active:Boolean read FActive write SetActive;  end;
    var
      CheckTCPClients:TObjectList;
      CheckTCPServer:TCheckTCPServer;
    //获得一个校验码
    function GetCheckStr:String;
    begin
      Result:=IntToStr(Random(8999)+1000);
    end;procedure RegUser(UserID,Password:String;var CheckStr:String);
    var
      PUI:TPUserInfo;
    begin
      GetMem(PUI,SizeOf(TUserInfo));
      PUI^.UserID:=UserID;
      PUI^.Password:=Password;
      CheckStr:=GetCheckStr;
      PUI^.CheckStr:=CheckStr;
      EnterCriticalSection(UserCS);
      UserList.Add(PUI);
      LeaveCriticalSection(UserCS);
    end;function NetCheckUser(UserID,Password:String;var CheckStr:String):Boolean;
    var
      i:Integer;
      UI:TUserInfo;
    begin
      UI.UserID:=UserID;
      UI.Password:=Password;
      UI.CheckStr:=CheckStr;
      Result:=False;
      for i:=0 to CheckTCPClients.Count-1 do
      begin
        with TIdTCPClient(CheckTCPClients.Items[i]) do
        begin
          if Connected then
          begin
            WriteBuffer(UI,SizeOf(UI),True);
            CheckStr:=ReadLn;
            if CheckStr<>'' then
            begin
              Result:=True;
              Break;
            end;
          end;
        end;
      end;
    end;function CheckUser(UserID,Password:String;var CheckStr:String):Boolean;
    var
      UserIndex:Integer;
      PUI:TPUserInfo;
    begin
      EnterCriticalSection(UserCS);
      UserIndex:=0;
      while UserIndex<UserList.Count do
      begin
        PUI:=TPUserInfo(UserList.Items[UserIndex]);
        if (PUI^.UserID=UserID)and(PUI^.Password=Password)then Break;
        Inc(UserIndex);
      end;
      if UserIndex<UserList.Count then
      begin//如果帐号已登陆
        if CheckStr=PUI^.CheckStr then
        begin//校验码符合,为了解决客户断线,重新登陆
          CheckStr:='';
          FreeMem(PUI);
          UserList.Delete(UserIndex);
        end
        else//校验码不符合
          CheckStr:=PUI^.CheckStr;
        Result:=True;
      end
      else
      begin
        CheckStr:='';
        Result:=False;
      end;
      LeaveCriticalSection(UserCS);
    end;procedure ConfigServers(Servers:Array of TServerInfo);
    var
      i:Integer;
      tTCPC:TIdTCPClient;
    begin
      for i:=Low(Servers) to High(Servers) do
      begin
        tTCPC:=TIdTCPClient.Create(nil);
        tTCPC.Host:=Servers[i].IP;
        tTCPC.Port:=Servers[i].Port;
        CheckTCPClients.Add(tTCPC);
      end;
    end;
    procedure BeginServerLink;
    var
      i:Integer;
    begin
      for i:=0 to CheckTCPClients.Count-1 do
      begin
        with TIdTCPClient(CheckTCPClients.Items[i]) do
        begin
          Connect;
        end;
      end;
    end;procedure EndServerLink;
    var
      i:Integer;
    begin
      for i:=0 to CheckTCPClients.Count-1 do
      begin
        with TIdTCPClient(CheckTCPClients.Items[i]) do
        begin
          Disconnect;
        end;
      end;
    end;procedure FreeUserList;
    var
      i:Integer;
    begin
      for i:=0 to UserList.Count-1 do FreeMem(UserList.Items[i]);
      UserList.Free;
    end;procedure OpenCheckServer(Port:Integer);
    begin
      CheckTCPServer.Active:=False;
      CheckTCPServer.Port:=Port;
      CheckTCPServer.Active:=True;
    end;{ TCheckTCPServer }constructor TCheckTCPServer.Create;
    begin
      TCPServer:=TIdTCPServer.Create(nil);
      TCPServer.OnExecute:=Execute;
    end;destructor TCheckTCPServer.Destory;
    begin
      TCPServer.Free;
    end;procedure TCheckTCPServer.Execute(AThread: TIdPeerThread);
    var
      UI:TUserInfo;
      CheckStr:String;
    begin
      try
        with AThread,Connection do
        begin
          ReadBuffer(UI,SizeOf(UI));
          CheckStr:=UI.CheckStr;
          CheckUser(UI.UserID,UI.Password,CheckStr);
          WriteLn(CheckStr);
        end;
      except
        on E:Exception do  AThread.Stop;
      end;
    end;procedure TCheckTCPServer.SetActive(const Value: Boolean);
    begin
      FActive := Value;
      TCPServer.Active:=Value;
    end;procedure TCheckTCPServer.SetPort(const Value: Integer);
    begin
      if not TCPServer.Active then
      begin
        with TCPServer.Bindings do
        begin
          Clear;
          Add.Port:=Value;
        end;
        FPort := Value;
      end;
    end;initialization
      UserList:=TList.Create;
      CheckTCPClients:=TObjectList.Create(True);
      CheckTCPServer:=TCheckTCPServer.Create;
      InitializeCriticalSection(UserCS);
    finalization
      FreeUserList;
      CheckTCPClients.Free;
      CheckTCPServer.Free;
      DeleteCriticalSection(UserCS);
    end.
      

  8.   

    //在应用程序服务器中插入如下语句,打开网络认证
    uses
      CheckUserUnit;
    const
      //联合认证服务器的的定义
      //!!注意:不要在此包含本机信息
      Servers:array[0..2]of TServerInfo=((IP:'192.168.0.169';Port:202),
                                         (IP:'192.168.0.170';Port:202),
                                         (IP:'192.168.0.168';Port:202));procedure TSerMainForm.FormCreate(Sender: TObject);
    begin
      ConfigServers(Servers);//注册联合认证服务器
      OpenCheckServer(202);//打开本地联合认证服务器
      BeginServerLink;//打开网络联合认证服务
    end;
    //在远程数据模块提供登陆接口函数供客户端调用如下:
    procedure TTestUserLogin.Login(const UserID, Password: WideString;
      var CheckStr: OleVariant);
    var
      CKS:String;
    begin
      CKS:=CheckStr;
      if   CheckUser(UserID,Password,CKS)
        or NetCheckUser(UserID,Password,CKS) then//检测用户在本地和远程的认证信息
      begin
        if CKS<>'' then
          CKS:=''
        else
          RegUser(UserID,Password,CKS);//在本地注册用户
      end
      else
        RegUser(UserID,Password,CKS);//在本地注册用户
      CheckStr:=CKS;
      if CheckStr<>'' then
        //打开应用程序服务器服务
      else
        //关闭应用程序服务器服务
    end;
    //客户端在登陆时除了输入用户名和密码外还要输入上次登陆的校验码(第一次登陆不输),
    //同时服务器返回本次登陆的校验码,空则说明登陆失败!
      

  9.   

    to: wizardqi(男巫) ( ) 信誉:100 
    不好意思,好长时间没有上论坛了,想不到阁下对小弟的问题如此重视,先谢了
    看了你的代码和思路,但仍然不是很明白,想详细问一下,不知道可否?
    我的msn:[email protected],肯请加我!
    对以上的代码的我有些愚问:
    一、针对你的思路,我还想进一步确认以下:服务器是不是为多个?1、验证服务器,2、数据库服务器
    二、CheckUserUnit与SerMainForm是同一程序中的不同单元吗?
    三、对procedure TTestUserLogin.Login(const UserID, Password: WideString;
    客户端如何调用验证服务中的函数?
    四、我的服务器只有一台,那么数据库和验证服务是否可以一起放到该机器上?
    五、Servers:array[0..2]of TServerInfo=((IP:'192.168.0.169';Port:202),
                                         (IP:'192.168.0.170';Port:202),
                                         (IP:'192.168.0.168';Port:202));
        是存放多个验证服务器的ip吗?
    以上的问题,肯请大侠能够告知,最好能够详谈一下,不好意思,本人太弱了,别见怪
    分是肯定会给的,这点请你放心!再谢了!
      

  10.   

    如果在sql server 下,他的用户表中有用户登录信息
      

  11.   

    呵呵,我没有MSN或着ICQ甚至于OICQ(QQ)号,还是就地解决你的问题吧:
    一、针对你的思路,我还想进一步确认以下:服务器是不是为多个?1、验证服务器,2、数据库服务器
    答:直到看到楼主由此一问才真正了解楼主的意思,原来楼主的要求比想象的要容易许多,如果只是一台服务器提供服务,就没有必要进行多服务器联合认证,使用数据库记录登陆信息就行了,当然如果只是检测帐号的使用,也没必要动用数据库,因为没必要为了检测一个非法用户而浪费一次数据库连接,以下是一个简易登陆验证函数,只需稍加修改(就像我上面的代码加上临界区保护)即可:
    //在远程数据模块提供登陆接口函数供客户端调用如下:
    var
      UserList,LogUserList:TStringList;//记着使用前初始化
    procedure TTestUserLogin.Login(const UserID, Password: WideString;
    var RetV: OleVariant);
    begin
      RetV:=(UserList.IndexOf(UserID+'|'+Password)>=0)and(LogUserList.IndexOf(UserID+'|'+Password)<0);
      if RetV then//如果本用户没有登陆
      begin
        LogUserList.Add(UserID+'|'+Password);
        OpenServer;//打开服务:比如数据库,准备缓冲,服务预处理等。
      end;
    end;
    //使用这个函数对客户进行简单身份认证(记着在没用正确认证前不要打开数据库,服务预处理等)。
    //对于客户端只需作如下调用即可:
    procedure ClientLoginForm.LoginBtnClick(Sender:TObject);
    var
      RetV:OleVariant;
    begin
      RDMConnection.AppServer.Login(UserName,Password,RetV);
      if RetV then
      begin
        ShowMessage('登陆成功!')
        //登陆成功处理
      end
      else
      begin
        ShowMessage('登陆失败,你的帐号已经被人使用!');
        //登陆失败处理
      end;
    end;
    //当然这个答案针对于问题"三、对procedure TTestUserLogin.Login(const UserID, Password: WideString;)客户端如何调用验证服务中的函数?".
    二、CheckUserUnit与SerMainForm是同一程序中的不同单元吗?
    答:是的,CheckUserUnit只是我实现多台服务器无共用数据库环境下联合认证的一个单元,提供了类似应用的功能函数。
    对于以下的问题我想也没必要回答了(相信楼主应该明白我的意思)。
    四、我的服务器只有一台,那么数据库和验证服务是否可以一起放到该机器上?
    五、Servers:array[0..2]of TServerInfo=((IP:'192.168.0.169';Port:202),
    (IP:'192.168.0.170';Port:202),
    (IP:'192.168.0.168';Port:202));