看看我的框架:
TClient = class
private
TSocketService: TSocketService;
//客户的Socket信息
FSocket: TSocket;
FAddr: TSockAddrIn;
FHostEnt: THostEnt;
//客户的登录信息
FSeat: Integer;
FID: Integer;
FCookie: Integer;
FName: string;
//客户数据包队列
FRecvPacket: TPacket; //收包只有一个
FSendPackets: TPackets; //发包可是一个队列
protected
procedure EnsureLogin(AID, ACookie: Integer; const AName: string); virtual;
public
constructor Create(SocketService: TSocketService; Sock: TSocket; Seat: Integer);
destructor Destroy; override;
//带PWD登录
function Login(const ID, Pwd: string): Boolean; overload;
//无PWD登录
function Login(const ID: string): Boolean; overload;
//如果没有正在传送的包,直接传送它,否则加到传送队列的最后
procedure Send(Packet: TPacket);
//传送一个错误信息
procedure SendError(const Msg: string);
//解析一个流为数据报,当有一个完整的数据报则处理这笔业务
//如果处理业务时涉及线程安全的部分交由TSocketService完成
procedure Receive(Packet: TPacket);
//调用Overlapped
procedure PostRecv;
procedure PostSend;
enbd;
TSocketService = class
private
//客户表(其中包括空座,以避免Delete操作)
FClients: TList;
//空座表
FEmptyList: TList;
FSection: TRTLCriticalSection;
FServicePort: Integer;
FActive: Boolean;
procedure Lock;
procedure Unlock;
//FClients.Count - FEmptyList.Count就是在线人数
function GetOnlineCount: Integer;
//FClients.Count就是峰值在线人数
function GetPeakCount: Integer;
protected
procedure SetActive(Value: Boolean); virtual;
function CreateClient(Sock: TSocket; Seat: Integer): TClient; virtual;
procedure ReleaseClient(Sender: TClient); virtual;
public
constructor Create(ServicePort: Integer);
destructor Destroy; override;
//线程排它操作
//仅仅只从FEmptyList取最后一个项,并从FEmptyList表中删除
//如果FEmptyList没有了,那就是FClient需要加一个空项,将Index返回
function OrderSeat: Integer;
//调用虚拟方法建立类实例,将Seat项加到FClients中
function EnsureSeat(Sock: TSocket; Seat: Integer): TClient;
//仅仅将Seat加到FEmptyList的最后
procedure CancelSeat(Seat: Integer);
//调用虚拟方法释放类实例,并将Seat加到FEmptyList的最后
procedure ReleaseSeat(Seat: Integer);
//呵呵,原来Seat就是FClient中的Index呀
function SeekSeat(Seat: Integer): TClient;
//通知数据已到或已发,由Worker线程调用
procedure Fire(Seat: Integer; Packet: TPacket; Bytes: Integer);
//属性
property OnlineCount: Integer read GetOnlineCount;
property PeakCount: Integer read GetPeakCount;
property Active: Boolean read FActive write SetActive;
end;