www.pudn.com > 2004021618574529928.rar > MainForm.pas


//技术讨论群组软件 
//开发者:张国伟 
//2004-2-7  QQ:38326155 
 
unit MainForm; 
 
interface 
 
uses 
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls, ComCtrls, ExtCtrls, ScktComp, DB, ADODB, Winsock, StrUtils, 
  TrayBarIcon; 
 
type 
    POnlineInf=^TOnlineInf; 
    TOnlineInf=record    //在线主机信息 
        UserName:String[255];     //用户标识 
        ControlSoc:TSocket;     //客户机控制信号套接字 
    end; 
 
type 
  TfrmMain = class(TForm) 
    Panel1: TPanel; 
    Panel2: TPanel; 
    SSEListUser: TListBox; 
    Panel3: TPanel; 
    RELog: TRichEdit; 
    TCPData: TServerSocket; 
    StatusBar1: TStatusBar; 
    ADOConnection: TADOConnection; 
    ADOQuery: TADOQuery; 
    Label1: TLabel; 
    Timer: TTimer; 
    TrayIcon: TTrayIcon; 
    procedure TCPDataClientRead(Sender: TObject; Socket: TCustomWinSocket); 
    procedure FormCreate(Sender: TObject); 
    procedure FormClose(Sender: TObject; var Action: TCloseAction); 
    procedure TCPDataClientDisconnect(Sender: TObject; 
      Socket: TCustomWinSocket); 
    procedure TimerTimer(Sender: TObject); 
    procedure TCPDataClientError(Sender: TObject; Socket: TCustomWinSocket; 
      ErrorEvent: TErrorEvent; var ErrorCode: Integer); 
    procedure TrayIconDblClick(Sender: TObject); 
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
  private 
    { Private declarations } 
  public 
    { Public declarations } 
    procedure SendOnlinesInfo; 
  end; 
 
var 
  frmMain: TfrmMain; 
  Onlines:TList; 
  MaxClient:Integer=1000; 
 
implementation 
 
uses UnitFunction; 
 
{$R *.dfm} 
 
procedure TfrmMain.SendOnlinesInfo; 
var 
    Buf:array of Byte; 
    I:Integer; 
    Len,TempLen:Integer; 
begin 
    SetLength(Buf,16 + SizeOf(Integer)); 
    for I:= 0 to 16 - 1 do 
    begin 
        if ((I mod 2) = 0) then Buf[I]:=$A 
        else Buf[I]:=$F; 
    end; 
    PInteger(@Buf[16])^:=Onlines.Count; 
 
    for I:= 0 to Onlines.Count - 1 do 
    begin 
        Len:=LengTh(POnlineInf(Onlines.Items[I]).UserName); 
        TempLen:=LengTh(Buf); 
        SetLength(Buf,TempLen + Len + 1 + SizeOf(Integer)); 
        CopyMemory(@Buf[TempLen],@POnlineInf(Onlines.Items[I]).UserName[1],Len); 
        Buf[TempLen + Len]:=0; 
        PInteger(@Buf[TempLen + Len +1])^:=POnlineInf(Onlines.Items[I]).ControlSoc; 
    end; 
    Len:=LengTh(Buf); 
    for I:= 0 to Onlines.Count - 1 do 
    begin 
        send(POnlineInf(Onlines.Items[I]).ControlSoc,Buf[0],Len,0); 
        Sleep(0); 
    end; 
end; 
 
procedure TfrmMain.TCPDataClientRead(Sender: TObject; 
  Socket: TCustomWinSocket); 
    procedure AddUserInfo(UserName:String;Control:TSocket);   //记录登录主机信息 
    var 
        TempInf:POnlineInf; 
        I:Integer; 
    begin 
        if SSEListUser.Items.Count >= MaxClient then 
        begin 
            Socket.SendText('$Z$MaxClient'); 
            with RELog do      //写入事件日志 
            begin 
                Lines.Add(DateTimeToStr(Now)); 
                Lines.Add(UserName+' 连接'); 
                Lines.Add('登录已拒绝,因服务器已达到最高人数'); 
                Lines.Add('远程位置: '+Socket.RemoteAddress); 
                Lines.Add(''); 
            end; 
            Exit; 
        end; 
        TempInf:=New(POnlineInf); 
        if SSEListUser.Items.Count > 0 then 
        begin 
            for I:= 0 to SSEListUser.Items.Count - 1 do                   //处理相同用户名 
            begin 
                if UserName = SSEListUser.Items.Strings[I] then 
                begin 
                        Socket.SendText('$Z$Logon'); 
                        with RELog do      //写入事件日志 
                        begin 
                            Lines.Add(DateTimeToStr(Now)); 
                            Lines.Add(UserName+' 连接'); 
                            Lines.Add('登录已拒绝,因用户名相同'); 
                            Lines.Add('远程位置: '+Socket.RemoteAddress); 
                            Lines.Add(''); 
                        end; 
                        Exit; 
                end; 
            end; 
        end; 
        TempInf.ControlSoc:=Control; 
        TempInf.UserName:=UserName; 
        Onlines.Add(TempInf); 
        SSEListUser.Items.Add(TempInf.UserName); 
        with RELog do      //写入事件日志 
        begin 
            Lines.Add(DateTimeToStr(Now)); 
            Lines.Add(TempInf.UserName+' 连接'); 
            Lines.Add('远程位置: '+Socket.RemoteAddress); 
            Lines.Add(''); 
        end; 
        Sleep(0); 
        SendOnlinesInfo; 
    end; 
 
    procedure DelUserInfo(UserName:String;Control:TSocket);   //删除登录主机信息 
    var 
        TempInf:POnlineInf; 
        I:Integer; 
        TempCount:Integer; 
    begin 
        TempInf:=New(POnlineInf); 
        TempInf.ControlSoc:=Control; 
        TempInf.UserName:=UserName; 
        TempCount:=Onlines.Count - 1; 
        for i:=0 to TempCount do 
        if (POnlineInf(Onlines.Items[I]).UserName = UserName) and (POnlineInf(Onlines.Items[I]).ControlSoc = TempInf.ControlSoc) then 
            begin 
                Dispose(Onlines.Items[I]); 
                Onlines.Delete(I); 
                Break; 
            end; 
        TempCount:=SSEListUser.Items.Count - 1; 
        for I:=0 to TempCount do 
            if TempInf.UserName = SSEListUser.Items[I] then 
            begin 
                if SSEListUser.Items.IndexOf(TempInf.UserName) <> -1  then 
                SSEListUser.Items.Delete(SSEListUser.Items.IndexOf(TempInf.UserName)); 
                Break; 
            end; 
        with RELog do      //写入事件日志 
        begin 
            Lines.Add(DateTimeToStr(Now)); 
            Lines.Add(TempInf.UserName+' 退出'); 
            Lines.Add('远程位置: '+Socket.RemoteAddress); 
            Lines.Add(''); 
        end; 
        SendOnlinesInfo; 
    end; 
 
    procedure TalkInfo(InBuf:array of Byte;Len:Integer;S:TSocket);    //转发聊天信息 
    var 
        I:Integer; 
        SourceName:String; 
        TalkStr:String; 
        TIdNum:Integer; 
        BasePos:Integer; 
        TargetName:String; 
        TempBuf:array of Byte; 
        ProcessBuf:array of Byte; 
        TempContent:String; 
    begin 
        SetLength(TempBuf,Len);    //开辟临时内存块 
        CopyMemory(@TempBuf[0],@InBuf[0],Len); 
 
        BasePos:=16;               //超始位置 
 
        SetLength(ProcessBuf,Len + SizeOf(Integer)); 
        CopyMemory(@ProcessBuf[0],@TempBuf[0],BasePos); 
 
        TIdNum:=Pinteger(@InBuf[BasePos])^;             //取得收信息者 Socket 句柄 
 
        Pinteger(@ProcessBuf[Basepos])^:=S;     //填充发送者 Socket 句柄 
        Inc(BasePos,SizeOf(Integer)); 
 
        Pinteger(@ProcessBuf[BasePos])^:=TIdNum; //填充收信息 Socket 句柄 
        Inc(BasePos,SizeOf(Integer)); 
 
        TempContent:=GetChatContent(TempBuf,LengTh(TempBuf));    //获取信息内容 
 
        CopyMemory(@ProcessBuf[BasePos],@TempContent[1],LengTh(TempContent)); //填充信息内容 
        ProcessBuf[Length(ProcessBuf) - 1]:=0; 
 
        begin 
            for I:= 0 to Onlines.Count - 1 do 
                send(POnlineInf(Onlines.Items[I]).ControlSoc,ProcessBuf[0],Length(ProcessBuf),0); 
        end; 
    end; 
var 
    Buf:array of Byte; 
    Data:WideString; 
    Len:Integer; 
    UserName, Pwd, Email:String; 
    DelControlData:String; 
    IsTalkInf:Boolean; 
    IsUpdateSMsg:Boolean; 
    I:Integer; 
    TempServerMsg:String; 
begin 
    Len:=Socket.ReceiveLength; 
    SetLength(Buf,Len); 
    Socket.ReceiveBuf(Buf[0],Len); 
    Data:=String(Buf); 
     
    if pos('$Z$Check',Data)=1 then  //用户名检测 
    begin 
        UserName:=Copy(Data,9,255); 
        with ADOQuery do 
        begin 
            Close; 
            SQL.Clear; 
            SQL.Add('select User_Name from UserInfo where User_Name='+''''+UserName+''''); 
            Open; 
        end; 
        if ADOQuery.RecordCount = 0 then 
            Socket.SendText('$Z$CanReg') 
        else 
            Socket.SendText('$Z$NoReg'); 
        //TCPData.Socket.Connections[TCPData.Socket.ActiveConnections - 1].Close; 
    end; 
 
    if pos('$Z$Reg',Data)=1 then  //注册 
    begin 
        DelControlData:=Copy(Data,7,255); 
        UserName:=Copy(Trim(DelControlData),1,Pos(' ',Trim(DelControlData))-1); 
        DelControlData:=Copy(DelControlData,LengTh(UserName) + 1,255); 
        Pwd:=Copy(Trim(DelControlData),1,Pos(' ',Trim(DelControlData))-1); 
        DelControlData:=Copy(DelControlData,LengTh(Pwd) + 2,255); 
        Email:=Copy(Trim(DelControlData),1,255); 
 
        with ADOQuery do 
        begin 
            Close; 
            SQL.Clear; 
            SQL.Add('select User_Name from UserInfo where User_Name='+''''+UserName+''''); 
            Open; 
        end; 
        if ADOQuery.RecordCount = 0 then 
        with ADOQuery do 
        begin 
            Close; 
            SQL.Clear; 
            SQL.Add('insert into UserInfo values '+'('+ '''' + UserName + '''' + ',' + '''' + Pwd + '''' + ',' + '''' + Email + '''' + ',' + '0' + ',' + '''' + DateTimeToStr(Now) + '''' + ')'); 
            ExecSQL; 
            Socket.SendText('$Z$CompleteReg'); 
             //发送注册用户数 
            begin 
                with ADOQuery do 
                begin 
                    Close; 
                    SQL.Clear; 
                    SQL.Add('select * from UserInfo'); 
                    Open; 
                end; 
                for I:= 0 to TCPData.Socket.ActiveConnections - 1 do 
                begin 
                    TCPData.Socket.Connections[I].SendText('$Z$AllCount' + IntToStr(ADOQuery.RecordCount)); 
                end; 
            end; 
        end 
        else 
            Socket.SendText('$Z$NoReg'); 
    end; 
 
    if pos('$Z$Login',Data)=1 then 
    begin 
        DelControlData:=Copy(Data,9,255); 
        UserName:=Copy(Trim(DelControlData),1,pos(' ',Trim(DelControlData))-1); 
        Pwd:=copy(Trim(DelControlData),pos(' ',Trim(DelControlData))+1,length(Trim(DelControlData))-pos(' ',Trim(DelControlData))); 
        with ADOQuery do 
        begin 
            Close; 
            SQL.Clear; 
            SQL.Add('select * from UserInfo where User_Name=' + '''' + UserName + ''''); 
            Open; 
        end; 
        if ADOQuery.RecordCount = 0 then 
        begin 
            Socket.SendText('$Z$NoUser'); 
            Exit; 
        end 
        else 
        begin 
            with ADOQuery do 
            begin 
                Close; 
                SQL.Clear; 
                SQL.Add('select User_Pwd from UserInfo where User_Name=' + '''' + UserName + ''''); 
                Open; 
            end; 
            if Pwd = ADOQuery.FieldByName('User_Pwd').AsString then 
            begin 
                Socket.SendText('$Z$LoginOk'); 
                AddUserInfo(UserName,Socket.SocketHandle); 
            end 
            else 
                Socket.SendText('$Z$NoPwd');  
        end; 
        SendOnlinesInfo; 
    end; 
 
    if pos('$Z$OneCount',Data)=1 then  //发送注册用户数 
    begin 
        with ADOQuery do 
        begin 
            Close; 
            SQL.Clear; 
            SQL.Add('select * from UserInfo'); 
            Open; 
        end; 
        Sleep(200);  
        Socket.SendText('$Z$OneCount' + IntToStr(ADOQuery.RecordCount)); 
    end; 
 
    if pos('$Z$GetServerMsg',Data)=1 then  //要求服务器消息 
    begin 
        SendServerMsg(GetServerMsg,Socket.SocketHandle); 
    end; 
 
    if pos('',Data)=1 then  //要求服务器广播登录消息  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
    begin 
        TempServerMsg:=GetServerMsg; 
        for I:= 0 to Onlines.Count - 1 do 
        begin 
           SendServerMsg(TempServerMsg,POnlineInf(Onlines.Items[I]).ControlSoc); 
           Sleep(0); 
        end; 
    end; 
 
    if pos('',Data)=1 then  //要求服务器广播临时消息  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
    begin 
        TempServerMsg:=Copy(Data,20,2000); 
        for I:= 0 to Onlines.Count - 1 do 
        begin 
           SendServerMsg(TempServerMsg,POnlineInf(Onlines.Items[I]).ControlSoc); 
           Sleep(0); 
        end; 
    end; 
 
    if pos('$Z$Out',Data)=1 then  //退出 
    begin 
        UserName:=Copy(Data,7,255); 
        DelUserInfo(UserName,Socket.SocketHandle); 
    end; 
 
    IsTalkInf:=True; 
    for I:= 0 to 16 - 1 do 
    begin 
        if ((I mod 2) = 0) then IsTalkInf:=IsTalkInf and (Buf[I]=$F) 
        else IsTalkInf:=IsTalkInf and (Buf[I]=$A); 
        if not IsTalkInf then Break; 
    end; 
    if IsTalkInf then TalkInfo(Buf,Len,Socket.SocketHandle); 
 
    IsUpdateSMsg:=True;     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
    for I:= 0 to 16 - 1 do 
    begin 
        if ((I mod 2) = 0) then IsUpdateSMsg:=IsUpdateSMsg and (Buf[I]=$B) 
        else IsUpdateSMsg:=IsUpdateSMsg and (Buf[I]=$F); 
        if not IsUpdateSMsg then Break; 
    end; 
    if IsUpdateSMsg then UpdateSMsg(Buf,Len); 
end; 
 
procedure TfrmMain.FormCreate(Sender: TObject); 
begin 
    Onlines:=TList.Create; 
    TrayIcon.Icon:=Application.Icon; 
end; 
 
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
    Onlines.Free; 
end; 
 
procedure TfrmMain.TCPDataClientDisconnect(Sender: TObject; 
  Socket: TCustomWinSocket); 
var 
    I:Integer; 
    TemStr:String; 
    TempCount:Integer; 
begin 
    TempCount:=Onlines.Count - 1; 
    for I:=0 to TempCount do 
        if (POnlineInf(Onlines.Items[I]).ControlSoc = Socket.SocketHandle) then 
        begin 
            TemStr:=POnlineInf(Onlines.Items[I]).UserName; 
            Dispose(Onlines.Items[I]); 
            Onlines.Delete(I); 
            Break; 
        end; 
    TempCount:=SSEListUser.Items.Count - 1; 
    for I:=0 to TempCount do 
        if Pos(TemStr,SSEListUser.Items[I]) <> 0 then  
        begin 
            if SSEListUser.Items.IndexOf(TemStr) <> -1  then 
            SSEListUser.Items.Delete(SSEListUser.Items.IndexOf(TemStr)); 
            Break;  
        end; 
        with RELog do      //写入事件日志 
        begin 
            Lines.Add(DateTimeToStr(Now)); 
            Lines.Add('客户机连接断开'); 
            Lines.Add('远程位置: '+Socket.RemoteAddress); 
            Lines.Add(''); 
        end; 
        SendOnlinesInfo; 
end; 
 
procedure TfrmMain.TimerTimer(Sender: TObject); 
begin 
    StatusBar1.Panels[0].Text:=Format('共有  %s  人在线',[IntToStr(SSEListUser.Count)]);  
end; 
 
procedure TfrmMain.TCPDataClientError(Sender: TObject; 
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; 
  var ErrorCode: Integer); 
begin 
    ErrorCode:=0; 
end; 
 
procedure TfrmMain.TrayIconDblClick(Sender: TObject); 
begin 
    TrayIcon.ShowMainForm; 
    SetForegroundWindow(frmMain.Handle); 
end; 
 
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 
    if Application.messagebox('关闭服务器程式将导致全部用户无法使用群组讨论服务,您确认吗?','执行确认',MB_YESNO + MB_DEFBUTTON2 + MB_ICONWARNING + MB_TASKMODAL)=IDNO then 
       Abort; 
end; 
 
end.