|
|
导航: |
论坛 -> DELPHI技术
斑竹:liumazi,sephil |
|
作者: |
jfhyn (贺兰之边) |
★☆☆☆☆ |
-
|
普通会员 |
|
2019/5/9 21:57:01 |
标题: |
请教大家,Delphi-Cross-Socket的UserData,UserObject的用法 |
浏览:1907 |
|
加入我的收藏 |
楼主: |
Delphi-Cross-Socket的TestCrossSocket中,我发送数据增加UserData数据,但是在服务端却接收不到. //客户端 procedure TfmMain.Button2Click(Sender: TObject); const DATA_SIZE = 10 * 1024 * 1024; var LStream: TBytesStream; LConns: TArray<ICrossConnection>; I: Integer; B: Byte; begin LConns := FSocket.LockConnections.Values.ToArray; if (LConns <> nil) then begin LStream := TBytesStream.Create(nil); for I := 1 to DATA_SIZE do begin B := RandomRange(0, 255 + 1); LStream.Write(B, SizeOf(Byte)); end; LStream.Position := 0; //增加的UserData数据---------- LConns[0].UserData := PChar('abcdefg'); LConns[0].SendStream(LStream, procedure(AConnection: ICrossConnection; ASuccess: Boolean) begin TThread.Queue(nil, procedure begin if ASuccess then ShowMessage( 'SendStream SUCCESS!!' + FSendCount.ToString) else ShowMessage('SendStream FAILED!!'); end); FreeAndNil(LStream); end); end; FSocket.UnlockConnections; end; 服务端 procedure TfmMain.OnReceived(Sender: TObject; AConnection: ICrossConnection; ABuf: Pointer; ALen: Integer); begin //此处接收不到数据,一直是nil---------- if AConnection.UserData <> nil then log(PChar(AConnection.UserData)); AtomicIncrement(FRcvdCount); AtomicIncrement(FRcvdBytes, ALen); end;
不知道为什么,恳请大神指导一下.
----------------------------------------------
- |
作者: |
|
2019/5/9 23:25:51 |
1楼: |
应该你没有分配内存,过程结束后系统回收了字符串的内存造成的,我这是没有问题的. 唯一不同的是我这是结构体而且是手动分配内存的.
----------------------------------------------
|
作者: |
|
2019/5/10 15:15:51 |
2楼: |
可以把UserData写到LStream里一起发送了,这样做需要客户端处理下粘包
----------------------------------------------
18114532@qq.com
|
作者: |
|
2019/5/10 17:09:41 |
3楼: |
个人觉得CrossSocket对有经验的开发人员更合适,而DIOCP适合注重应用层面的人士,我个人把DIOCP中的MsgPack类用到CrossSocket中然后写了粘包处理,算是二者的结合吧。如果有需要我可以发给你。
----------------------------------------------
18114532@qq.com
|
作者: |
jfhyn (贺兰之边) |
★☆☆☆☆ |
-
|
普通会员 |
|
2019/5/10 23:17:51 |
4楼: |
现在明白了UserData等的用法,是为了附加信息,处理发送或者返回数据的完整性. 谢谢大家! @abcjingtong 3楼兄弟,能否把Demo发给我学习一下,谢谢!
----------------------------------------------
-
|
作者: |
|
2020/1/31 11:58:57 |
5楼: |
@abcjingtong 兄弟,能否把Demo 提供出来,学习学习,感谢!谢谢!
----------------------------------------------
-
|
作者: |
jfhyn (贺兰之边) |
★☆☆☆☆ |
-
|
普通会员 |
|
2020/1/31 13:22:59 |
6楼: |
@akuan54 UserObject UserData就是为了方便处理数据的,接收或者发送时创建一个UserObject就行,我有时会把DataSet传给UserData.
----------------------------------------------
-
|
作者: |
|
2020/1/31 14:58:33 |
7楼: |
@jfhyn 谢谢您的说明。会再研究看看的。
对于 @abcjingtong 有关 [MsgPack类用到CrossSocket中然后写了粘包处理] 这部份有兴趣,希望 @abcjingtong 有时间的话可以发出来提供大家学习。感谢。
----------------------------------------------
-
|
作者: |
|
2020/1/31 19:10:45 |
8楼: |
对不起,因为自己的忙一直没有回复大家的需求,我现在始写一下,今晚21点前应该可以完成
----------------------------------------------
18114532@qq.com
|
作者: |
|
2020/1/31 20:16:39 |
9楼: |
由于Socket的分片传输机制,Socket接收端每次接收的数据其实也是一个个片断(具体片断大小怎么分请见相关的协议),所以需要对接收到的数据判断是否完整,以便将完整的数据交到业务逻辑里处理。 Socket通讯双方都有一个连接对象Connection,CrossSocket也不例外,所有的Socket事件几乎都有这个参数,比如 procedure THCRSocket.LogicConnected(AConnection: ICrossConnection); procedure THCRSocket.LogicDisconnected(AConnection: ICrossConnection); procedure THCRSocket.LogicReceived(AConnection: ICrossConnection; ABuf: Pointer; ALen: Integer); 为了处理粘包,我们需要有一个对象,能记录下来当前接收的数据,并在接收数据前绑定到Connection上面, 这样之后Connection就一直能有这个对象供我们操作了,比如我创建了一个叫TBufferLink的对象, 在连接一旦建立就绑定到UserObject上 procedure THCRSocket.LogicConnected(AConnection: ICrossConnection); begin inherited LogicConnected(AConnection); AConnection.UserObject := TBufferLink.Create; end; 当然,如果连接断开了,就把这个对象释放掉 procedure THCRSocket.LogicDisconnected(AConnection: ICrossConnection); begin inherited LogicDisconnected(AConnection); if Assigned(AConnection.UserObject) then TBufferLink(AConnection.UserObject).Free; end; 在每次收到数据时,把收到的数据拼装到这个TBufferLink里,并由它给出数据是否接收完整了, 注意接收到数据和接收完整是两个概念, procedure THCRSocket.LogicReceived(AConnection: ICrossConnection; ABuf: Pointer; ALen: Integer); var vRecvBuffer: TBufferLink; vDecodeObj: TObject; begin inherited LogicReceived(AConnection, ABuf, ALen); vRecvBuffer := AConnection.UserObject as TBufferLink; vRecvBuffer.AddBuffer(ABuf, ALen); // 数据拼装
vDecodeObj := DecodeRecvBuffer(vRecvBuffer); // 返回数据是否接收完整 if Integer(vDecodeObj) = -1 then // 错误的包格式, 关闭连接 begin Active := False; Exit; end else if vDecodeObj <> nil then // 接收完整了 begin try if Assigned(FOnReceivedData) then // 交给业务逻辑处理 FOnReceivedData(AConnection, TBytesStream(vDecodeObj)); finally TBytesStream(vDecodeObj).Free; end; end; end; 具体DecodeRecvBuffer里的实现不算很复杂,但理解起来有点吃力,有需要了再讲吧,附上我自己封装的2个单元,如果还有缺少告诉我 HCSocket.pas里有THCRServer和THCRClient,可分别作为服务端和客户端的对象使用,如 FMsgServer := THCRServer.Create; FMsgServer.Port := 12820; FMsgServer.OnConnected := DoServerConnected; FMsgServer.OnDisconnected := DoServerDisconnected; FMsgServer.OnReceiveData := DoServerReceiveData; FMsgServer.OnError := DoServerError;
----------------------------------------------
18114532@qq.com
|
作者: |
|
2020/1/31 20:19:28 |
10楼: |
HCSocket.pas,自己改后缀
----------------------------------------------
18114532@qq.com
|
作者: |
|
2020/1/31 20:23:08 |
11楼: |
utils_buffer.pas,来自DIOCP非我原创,自己改后缀, 盒子这传文件不是一般的不稳定。
----------------------------------------------
18114532@qq.com
|
作者: |
|
2020/1/31 21:33:29 |
12楼: |
@abcjingtong 感激您的分享,定当好好学习一番。再次感谢。
----------------------------------------------
-
|
|