使用 TIdTcpServer 和 TIdTcpClient 数据通信 问题???

jxqn_liu 2012-07-18 09:55:50
需求:

报文格式:数据包头 + 数据包体(数据包头的内容是不包含包头的整个数据包长度)。
|------------------|----------------|
|数据包头(56字节)| 数据包体 |
|------------------|----------------|
| Data Header | Data Body |
|------------------|----------------|

所有非数字字段左对齐,右补空格;金额右对齐,左补空格,精确到分。
报文体长度=56+数据包体长度。
报文编号:ABCDEF001;报文头格式:
|------|-----------|--------|--------|--------|------------|-------------------|
|序号 | 名称 | 类型 | 长度 | 对齐 | 填充字符 | 说明 |
|------|-----------|--------|--------|--------|------------|-------------------|
| 1 |报文体长度 | 数值 | 6 | Left | 空格 | 报文体长度 |
|------|-----------|--------|--------|--------|------------|-------------------|
| 2 |交易码 | 字符 | 6 | Left | 空格 | 交易码 |
|------|-----------|--------|--------|--------|------------|-------------------|
| 3 |返回码 | 字符 | 4 | Left | 空格 | 返回码 |
|------|-----------|--------|--------|--------|------------|-------------------|
| 4 |返回信息 | 字符 | 40 | Left | 空格 | 返回信息 |
|------|-----------|--------|--------|--------|------------|-------------------|

交易返回码定义:
   0000 交易成功
   1001 无用户号码
   9000 系统暂停服务
   9999 其它原因
   
报文内容(数据包体)格式 如:
查询请求报文
   报文编号:ABCDEF002;报文格式:
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 序号 | 名称 | 说明 | 类型 | 长度 | 精度 | 输入 | 备注 |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 1 |USERID | 用户编码 |Varchar | 20 | | Y |缴费用户编码 |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 2 |DATE | 交易日期 |Varchar | 8 | | N |YYYYMMDD(系统日期) |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 3 |TERM | 交费种类 |Char | 3 | | Y |101(默认值) |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
  
查询应答报文(系统应答数据)
   报文编号:ABCDEF003;报文格式:
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 序号 | 名称 | 说明 | 类型 | 长度 | 精度 | 输入 | 备注 |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 1 |USERID | 用户编码 |Varchar | 20 | | N |缴费用户编码 |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 2 |DATE | 交易日期 |Varchar | 8 | | N |YYYYMMDD(系统日期) |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 3 |TERM | 交费种类 |Char | 3 | | N |101(默认值) |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 4 |CustName | 客户名称 |Varchar | 40 | | N |客户姓名 |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 5 |CustAddr | 客户地址 |Varchar | 100 | | N |客户地址 |
|------|-----------|------------|--------|---------|--------|--------|----------------------|
| 6 |Money | 金额 |Numeric | 18 | 2 | N |金额 |
|------|-----------|------------|--------|---------|--------|--------|----------------------|



环境:
开发工具:Delphi7
使用控件:TIdTcpServer 和 TIdTcpClient
数据库:SQL2005

报文的格式数据即SQL数据表,在客户端通过请求报文向服务器发送,服务器根据请求报文的信息反馈相应的结果到客户端。

问题:
1.使用 TIdTcpServer 和 TIdTcpClient 能发送报文数据吗?如果不行的话,那请问用什么控件好点!
2.能发送的话,数据包头和数据包体的格式可以使用 Delphi 的 Record 来定义吗?
3.怎么在客户端和服务器之间传递数据包头和数据包体?


小弟之前都是做数据库开发的,现在接了个任务需要做网络通讯方面的,由于没接触过,也不知道从何下手!现在也就能使用 TIdTcpServer 和 TIdTcpClient 传递字符串!

还望各位大神不吝赐教!!谢谢大家!

分不是很多,这是最大分值!如果需要可以继续开帖!
...全文
257 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
jxqn_liu 2012-07-19
  • 打赏
  • 举报
回复
谢谢 li_sj(小人物)的解释和给出的示例,看了下示例,我心中大概知道怎么去实现了!

真的非常感谢!
li_sj 2012-07-19
  • 打赏
  • 举报
回复
这是服务端的

procedure TFormMain.IdUDPServer1UDPRead(Sender: TObject; AData: TBytes;
ABinding: TIdSocketHandle);
var
CMD : TCMD;
i : Integer;
LoginInfo : TLoginInfo;
LoginResPac: TLoginResPac; //登录返回信息包
PulseResPac: TPulseResPac; //心跳返回信息包
P : PLoginInfo;
Index : Integer;
sSoft_Type:string;
begin
Bytestoraw(AData,CMD,SizeOf(CMD));
case CMD.SoftType of
ST_Message:sSoft_Type:='信息系统';
ST_OA:sSoft_Type:='办公自动化系统';
ST_SalesPOS:sSoft_Type:='销售POS系统';
end;
Case CMD.CMD of
CT_LogIn:
begin
ZeroMemory(@LoginResPac,SizeOf(LoginResPac));
LoginResPac.MyIPNPort.Port := ABinding.PeerPort;
StrLCopy(LoginResPac.MyIPNPort.IP,PChar(ABinding.PeerIP),SizeOf(LoginResPac.MyIPNPort.IP) - 1);
LoginResPac.CMD.CMD := CCT_LoginRes; ABinding.SendTo(ABinding.PeerIP,ABinding.PeerPort,RawToBytes(LoginResPac,SizeOf(LoginResPac)));
//TestInsert(CMD);
MemoAdd(DateTimeToStr(now)+' '+sSoft_Type+' '+cmd.Code + ' 登录');
OnlineUpdate(cmd.Code,sSoft_Type,'1');
if cxRadioGroup1.ItemIndex =2 then OnlineShow ;
end;
CT_Pulse:
begin
ZeroMemory(@PulseResPac,SizeOf(PulseResPac));
PulseResPac.MyIPNPort.Port := ABinding.PeerPort;
StrLCopy(PulseResPac.MyIPNPort.IP,PChar(ABinding.PeerIP),SizeOf(PulseResPac.MyIPNPort.IP) - 1);
PulseResPac.CMD.CMD := CCT_PulseRes; ABinding.SendTo(ABinding.PeerIP,ABinding.PeerPort,RawToBytes(PulseResPac,SizeOf(LoginResPac)));
//TestInsert(CMD);
MemoAdd(DateTimeToStr(now)+' '+sSoft_Type+' '+cmd.Code + ' 心跳包');
OnlineUpdate(cmd.Code,sSoft_Type,'1');
end;
CT_logout:
begin
MemoAdd(DateTimeToStr(now)+' '+sSoft_Type+' '+cmd.Code + ' 退出');
OnlineUpdate(cmd.Code,sSoft_Type,'0');
if cxRadioGroup1.ItemIndex =2 then OnlineShow ;
end;
End;
end;
li_sj 2012-07-19
  • 打赏
  • 举报
回复
给你发个我之前写的心跳包——基于UDP

const
CT_login =$00000001; //登录
CT_Pulse =$00000002; //心跳
CT_logout =$00000003; //退出

type
TUserCode=array [0..20] of Char;
TIP=array [0..15] of Char;

TCMD=packed record
Code: TUserCode;
SoftType:DWORD;
CMD:DWORD;
end;
……
procedure TMainForm.PulsePack;
var
CMD : TCMD;
sUser:TUserCode;
begin
CMD.Code:=sUser ;
CMD.SoftType:=ST_OA;
CMD.CMD := CT_Pulse;
IdUDPServer1.SendBuffer(UdpIp,UdpPort,RawToBytes(CMD,SizeOf(CMD)));
end;
li_sj 2012-07-19
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

引用 8 楼 的回复:

建议看一下INDY的DEMO,里面有个CHAT的DEMO,比较详细,不过他的客户端好像没用多线程


谢谢!发送字符串这个到是简单,但是要发送数据包,这个不懂。

网上看了别人说什么“粘包”、“拆包”等术语,请教这个如何实现的?
[/Quote]

我在上面的原因已经很详细了,其实就是你的“粘包”、“拆包”
li_sj 2012-07-18
  • 打赏
  • 举报
回复
建几个自定义包就行了。
每个不同的信息建独立包。
一个主包,也就是每次发送的包,这个包有2个值,一个是包的类型,一个就是上面的信息包,服务器收到包后,先读取包类型,然后做个case 解读包信息就行了,返回也是如此。
kaikai_kk 2012-07-18
  • 打赏
  • 举报
回复
用记录类型就行了
jxqn_liu 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]

建议看一下INDY的DEMO,里面有个CHAT的DEMO,比较详细,不过他的客户端好像没用多线程
[/Quote]

谢谢!发送字符串这个到是简单,但是要发送数据包,这个不懂。

网上看了别人说什么“粘包”、“拆包”等术语,请教这个如何实现的?
shuihan20e 2012-07-18
  • 打赏
  • 举报
回复
建议看一下INDY的DEMO,里面有个CHAT的DEMO,比较详细,不过他的客户端好像没用多线程
jxqn_liu 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

要看你的需求了,如果是自己公司人员用的话,用三层方便多了。
[/Quote]
谢谢兄台,由于这只是一个小工具,个人认为还是不需要三层!再说公司用的架构还不是三层的!
li_sj 2012-07-18
  • 打赏
  • 举报
回复
要看你的需求了,如果是自己公司人员用的话,用三层方便多了。
jxqn_liu 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

你只需要将包定义好,发给服务器就行了,其他的控件自己会处理。至于返回,一般是客户端发给服务器,服务器直接返回的。也就是说客户端连接到服务器,服务器才会有数据返回。服务器是不会主动发数据到客户端的(我一般是这样做的,可能别人有其他方法)。
以上功能不是三言两语就能说地清的,你可以找找TCP、UDP发包DEMO,有详细发送和接收例子。
我个人不大建议使用这种模式,毕竟太麻……
[/Quote]
谢谢,我现在的流程就是在客户端发出请求后,服务端接收到请求后根据请求信息,反馈相应的请求数据!
不使用这种模式,兄台还有其他方面吗?还望赐教!
li_sj 2012-07-18
  • 打赏
  • 举报
回复
报文格式:数据包头 + 数据包体(数据包头的内容是不包含包头的整个数据包长度)。

你想地太复杂了,这又不是在写网游外挂。
其实这和自定义一个参数,然后赋值到一个过程中是一样的。

我前面说主包+信息包的方法,只是方便发一种格式数据包就行了。你完全可以只用信息包,前提是你的服务器能区分包的结构。
li_sj 2012-07-18
  • 打赏
  • 举报
回复
你只需要将包定义好,发给服务器就行了,其他的控件自己会处理。至于返回,一般是客户端发给服务器,服务器直接返回的。也就是说客户端连接到服务器,服务器才会有数据返回。服务器是不会主动发数据到客户端的(我一般是这样做的,可能别人有其他方法)。
以上功能不是三言两语就能说地清的,你可以找找TCP、UDP发包DEMO,有详细发送和接收例子。
我个人不大建议使用这种模式,毕竟太麻烦,功能一多,数据量一大就会很麻烦。
对于功能单一,流量不大情况下用用还是可以的。
jxqn_liu 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

建几个自定义包就行了。
每个不同的信息建独立包。
一个主包,也就是每次发送的包,这个包有2个值,一个是包的类型,一个就是上面的信息包,服务器收到包后,先读取包类型,然后做个case 解读包信息就行了,返回也是如此。
[/Quote]

数据包头不用发送吗?如果要返回,应该怎么做,也是加入到主包中,和信息包一起返回还是分开处理?

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧