C/S架构下,如何判断帐号已经登陆,如果该帐号已经登陆,那么将不允许其他机器通过该帐号登陆,请问各位如何解决该问题?用Com吗?
多谢各位了!
多谢各位了!
解决方案 »
- 那位给个msdn 2005里的下载地址。
- fastreport 横向打印的时候,预览正确,但是第一页每次都缺少右边一点?
- 有关Query的Filtered 问题,请高手指点!TKS!
- 我想生成'001','002',....'110'这样的字符串,可怎么样得到“'”这个字符?
- 急急急,在线等!解决马上给分!怎么样使执行过程的时候显示进度条?
- 把整个Word文档保存到数据库
- Win32中的服务本质是什么?怎么样把一个应用程序做成服务??
- 我最近编写一个DLL,用来实现ftp功能,使用了delphi中的nmftp控件,结束调用后总出现莫名其妙的内存错误。请高手指教!
- 在DBGird中怎样禁止‘向下’键
- Help!!关于使用SavetoFile!!
- 如何复制数据库的内容
- 怎么强制设定DBGrid的列宽
谢谢你的回答,这样解决的可行性是有的,但是是否便于管理呢,拓展性是否高呢?如果我想查看当前的登陆帐号数量呢?
因为可能会有客户端异常退出的情况,那样异常退出就不能再次登录了我的思路是做一个检测程序,定时检测客户程序是否正常运行(这个用socket就可以做到),对于异常退出的客户端删除他的登录信息,这样就解决了异常退出的情况
如果是上万的,可能就有不同的做法
异常退出时应该怎样处理?socket又怎样用呢?我还没用过这方面的东西,希望能得到你的解答,谢谢!!
用户数量:两位数
当然如果几个服务器有共享数据库最好,那实现起来容易许多,相信如果楼主需要这样的代码的话可能早有人帖了,好现在我做了一个在没有共享结构的情况下实现联合认证的代码,请楼主参考同一问题你所开的另一帖我所阐述的解决方案理解以下代码:
(*
本单元主要负责了在无共享数据库的环境下进行用户信息联合认证,提供一系列函数供参考
*)
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.
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;
//客户端在登陆时除了输入用户名和密码外还要输入上次登陆的校验码(第一次登陆不输),
//同时服务器返回本次登陆的校验码,空则说明登陆失败!
不好意思,好长时间没有上论坛了,想不到阁下对小弟的问题如此重视,先谢了
看了你的代码和思路,但仍然不是很明白,想详细问一下,不知道可否?
我的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吗?
以上的问题,肯请大侠能够告知,最好能够详谈一下,不好意思,本人太弱了,别见怪
分是肯定会给的,这点请你放心!再谢了!
一、针对你的思路,我还想进一步确认以下:服务器是不是为多个?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));