没有找到合适的产品?
联系客服协助选型:023-68661681
提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
翻译|其它|编辑:郝浩|2005-02-25 10:00:00.000|阅读 1876 次
概述:
# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>
3.程序执行到这里,得看看ClientSocket吧,有了上面的分析,下面的分析都会简单得多:
constructor TClientSocket.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FClientSocket := TClientWinSocket.Create(INVALID_SOCKET);
InitSocket(FClientSocket);
end;
没有什么值得讨论的FClientSocket也是继承父类的构造方法,上面已经说过了。
接设置Port,Address等,都是到祖先类设置,没有什么好说的,最后一句是
Active:=true;
上面的讨论已经知道,它最后会调用ClientSocket的覆盖方法:
procedure TClientSocket.DoActivate(Value: Boolean);
begin
if (Value <> FClientSocket.Connected) and not (csDesigning in ComponentState)
then
begin
if FClientSocket.Connected then
FClientSocket.Disconnect(FClientSocket.FSocket)
else FClientSocket.Open(FHost, FAddress, FService, FPort, ClientType =
ctBlocking);
end;
end;
这里的Value为True,则调用
FClientSocket.Open(FHost, FAddress, FService, FPort, ClientType = ctBlocking);
去看看吧:
procedure TCustomWinSocket.Open(const Name, Address, Service: string; Port:
Word; Block: Boolean);
begin
if FConnected then raise ESocketError.CreateRes(@sSocketAlreadyOpen);
FSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
if FSocket = INVALID_SOCKET then raise ESocketError.CreateRes(@sCannotCreateSocket);
try
Event(Self, seLookUp);
if Block then
begin
FAddr := InitSocket(Name, Address, Service, Port, True);
DoOpen;
end else
AsyncInitSocket(Name, Address, Service, Port, 0, True);
except
Disconnect(FSocket);
raise;
end;
end;
没什么特别之处,以我们设置的方式,也一样调用AsyncInitSocket,同样也是完成Socket的设置
再回去看看第2步中的代码吧,而它的Client参数是设为True,所以最后的一定会调用:
DoOpen:
procedure TCustomWinSocket.DoOpen;
begin
DoSetASyncStyles;
Event(Self, seConnecting);
CheckSocketResult(WinSock.connect(FSocket, FAddr, SizeOf(FAddr)), 'connect');
FLookupState := lsIdle;
if not (asConnect in FAsyncStyles) then
begin
FConnected := FSocket <> INVALID_SOCKET;
Event(Self, seConnect);
end;
end;
和上面说到的Dolisten简直像极了,这里也没有必多说了。我们已经可以向更加简单的第四步进发了。
4. ClientSocket向服务端连接后,WinSock会向服务端发送一个事件,,而上面已经过了事件获取函数:CMSocketMessage
其中的消息标识码是:FD_ACCEPT,所以会调用Accept(Socket);函数,这个与其他的事件方法不同,我们来看看它的源码就知道了:
procedure TCustomWinSocket.Accept(Socket: TSocket);
begin
end;
Socket的父类将这个方法设为虚方法,并什么事也不做,可知它的子类ServerWinSocket一定覆盖了这个方法,并可能要做一些线程分配方面的工作,但这又是一个大函数了,又要花一大篇来分析了,但离胜利之地已经不远了,这一步完成,其他就全部都是小菜一碟了。
(41)
procedure TServerWinSocket.Accept(Socket: TSocket);
var
ClientSocket: TServerClientWinSocket;
ClientWinSocket: TSocket;
Addr: TSockAddrIn;
Len: Integer;
OldOpenType, NewOpenType: Integer;
begin
Len := SizeOf(OldOpenType);
//得到与指定套接口相关的属性选项。
if getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType),
Len) = 0 then
try
if FServerType = stThreadBlocking then
begin
NewOpenType := SO_SYNCHRONOUS_NONALERT;
//设置与指定套接口相关的属性选项。
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@NewOpenType), Len);
end;
Len := SizeOf(Addr);
调用SocketAPI,返回一个新的套接字与客户端进行通信
ClientWinSocket := WinSock.accept(Socket, @Addr, @Len);
if ClientWinSocket <> INVALID_SOCKET then
begin
ClientSocket := GetClientSocket(ClientWinSocket);
if Assigned(FOnSocketEvent) then
FOnSocketEvent(Self, ClientSocket, seAccept);
if FServerType = stThreadBlocking then
begin
ClientSocket.ASyncStyles := [];
GetServerThread(ClientSocket);
end;
end;
finally
Len := SizeOf(OldOpenType);
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), Len);
end;
end;
我们只针对我们非阻塞模式来看几个重要的语句,上面已经用蓝色标识出来了。首先:
ClientWinSocket := WinSock.accept(Socket, @Addr, @Len);
调用WinSock的API,Accept得到一个与客户端进行通信的Socket,而原来的Socket则继续监听。
ClientSocket := GetClientSocket(ClientWinSocket);
ClientSocket是一个TServerClientWinSocket类的对象,这个对象就是代表与客户端通信的Socket类,那么GetClientSocket必定是以参数WinSocket创建了一个TServerClientWinSocket对象,看代码去:
(411)
function TServerWinSocket.GetClientSocket(Socket: TSocket):
TServerClientWinSocket;
begin
Result := nil;
if Assigned(FOnGetSocket) then FOnGetSocket(Self, Socket, Result);
if Result = nil then
Result := TServerClientWinSocket.Create(Socket, Self);
end;
果然其中创建了这个类的对象,不但传入了上面的WinSocket,还传递了ServerWinSocket自己,继续吧,不要言累:
(4111)
constructor TServerClientWinSocket.Create(Socket: TSocket; ServerWinSocket:
TServerWinSocket);
begin
FServerWinSocket := ServerWinSocket;
if Assigned(FServerWinSocket) then
begin
FServerWinSocket.AddClient(Self);
if FServerWinSocket.AsyncStyles <> [] then
begin
OnSocketEvent := FServerWinSocket.ClientEvent;
OnErrorEvent := FServerWinSocket.ClientError;
end;
end;
inherited Create(Socket);
if FServerWinSocket.ASyncStyles <> [] then DoSetAsyncStyles;
if FConnected then Event(Self, seConnect);
end;
这里两个重要的语句已经标出来了,第一句,它调用了传进来的ServerWinSocket的方法AddClient,看看这个怎么实现的:
(41111)
procedure TServerWinSocket.AddClient(AClient: TServerClientWinSocket);
begin
FListLock.Enter;
try
if FConnections.IndexOf(AClient) < 0 then
FConnections.Add(AClient);
finally
FListLock.Leave;
end;
end;
哈,这个方法的意思已经很明显了,他就是把这个与客户端的通信的Socket加入了一个列表中,这个列表已经在前面看到创建了的,便于以后维护。
上面函数接下的另一句inherited Create(Socket);则是其父类TCustomWinSocket的构造函数了,上面我们已经分析过了,就是将这个与客户端的连接的Socket赋给成员FSocket。
最后我们得回过头到Accept方法再去看最后一个重要语句:
FOnSocketEvent(Self, ClientSocket, seAccept);
OnAccept终于发生了,我们可以在这里事件中向客户端发送一些信息!
5.分析到这里,接下来就是WinSock的事了,客户端和服务端开始通信,于是它向这些类发送消息,然后传递事件处理函数,就可以进行非阻塞的数据传输,而那些数据传递函数最终也都是调用Socket的API,所以我想也不要多说了,看看源代码吧。大概的脉络其实在第2步中说得也差不多了。
执行到最后,会设Active为False,回顾上面的代码,则会调用Socket的父类:
TCustomWinSocket.Disconnect,不过ServerSokcet又覆盖了这个方法,它所完成的功能只是释放掉所有的线程,最后还是会调用父类的这个方法。
(51)
procedure TCustomWinSocket.Disconnect(Socket: TSocket);
begin
Lock;
try
if FLookupHandle <> 0 then
CheckSocketResult(WSACancelASyncRequest(FLookupHandle), 'WSACancelASyncRequest');
FLookupHandle := 0;
if (Socket = INVALID_SOCKET) or (Socket <> FSocket) then exit;
Event(Self, seDisconnect);
CheckSocketResult(closesocket(FSocket), 'closesocket');
FSocket := INVALID_SOCKET;
FAddr.sin_family := PF_INET;
FAddr.sin_addr.s_addr := INADDR_ANY;
FAddr.sin_port := 0;
FConnected := False;
FreeAndNil(FSendStream);
finally
Unlock;
end;
end;
CheckSocketResult(closesocket(FSocket), 'closesocket');这一句即完成了Socket的关闭了。
通信完后,两个类都要释放了,在析构函数中做一些收尾的工作,大想也可以猜它要做什么了。
先来看看ServerSocket的析构函数:
(52)
destructor TCustomServerSocket.Destroy;
begin
FServerSocket.Free;
inherited Destroy;//这是TComponent的析构函数
end;
先释放FServerSocket,再调用父类的析构函数,一个个来看。它到底做了些什么收尾的工作。
(521)
destructor TServerWinSocket.Destroy;
begin
inherited Destroy;
FConnections.Free;
FActiveThreads.Free;
FListLock.Free;
end;
没有什么可说的,再追上去:
(5211)
destructor TCustomWinSocket.Destroy;
begin
FOnSocketEvent := nil; { disable events }
if FConnected and (FSocket <> INVALID_SOCKET) then
Disconnect(FSocket);
//释放由AllocateHWnd.生成的窗口。
if FHandle <> 0 then DeallocateHWnd(FHandle);
FSocketLock.Free;
Cleanup;
FreeMem(FGetHostData);
FGetHostData := nil;
inherited Destroy;//这是TObject的析构函数
end;
看下去:
procedure Cleanup;
var
ErrorCode: Integer;
begin
ErrorCode := WSACleanup;
if ErrorCode <> 0 then
raise ESocketError.CreateResFmt(@sWindowsSocketError,
[SysErrorMessage(ErrorCode), ErrorCode, 'WSACleanup']);
end;
总算是最后了,看到SocketAPI的调用了吗。
那么ClientSocket的呢:
(53)
destructor TClientSocket.Destroy;
begin
FClientSocket.Free;
inherited Destroy; //这是TComponent的析构函数
end;
我们已经很有经验了,看FClientSocket的析构函数去,但ClientSocket没有构析函数,他的父类才有,即我们说到的TCustomWinSocket,那么一切都结束了。
这一大块,非阻塞式的一次操作就这样结束了。请各位对着源代码看吧,多跟踪一下,也许发现的东西比我还多。如果下次有机会,我会进行一次阻塞式的代码阅读的。
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com
面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@evget.com
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢
慧都科技 版权所有 Copyright 2003-
2025 渝ICP备12000582号-13 渝公网安备
50010702500608号