关于socket通讯有一事不明,望赐教???
使用TIdTCPClient.WriteBuffer发送一串16进制数据(长度不定),server端如何知道需要读多少个字节呢?有没可能server端只读取了半个包,或者一次读取了2个包。
另外TIdTCPClient没有Execute事件,如果只想被动的接受server端发送的数据,是否只能不停的去掉用ReadBuffer过程,读出的数据是否要和串口通讯一样在去组包。
欢迎高人回答,人人有分!!!
问题点数:100、回复次数:18Top
1 楼notruiyi(什么乱七八糟的)回复于 2005-08-03 13:45:14 得分 5
很少用这个DELPHI网络编程
可以先发送一个标志符+长度吗?Top
2 楼cjf1009(农民程序员)回复于 2005-08-03 14:11:37 得分 15
使用TIdTCPClient.WriteBuffer发送一串16进制数据(长度不定),server端如何知道需要读多少个字节呢?有没可能server端只读取了半个包,或者一次读取了2个包。
---------------------------------------------
server端要预先知道包的大小,用在线程里用athread.connection.readBuffer(block,sizeof(block))读取。他是阻塞式的,不会只读取了半个包,或者一次读取了2个包。
------------------------
另外TIdTCPClient没有Execute事件,如果只想被动的接受server端发送的数据,是否只能不停的去掉用ReadBuffer过程,读出的数据是否要和串口通讯一样在去组包。
---------------------------
TIdTCPClient一般开一个线程,在线程里ReadBuffer,来读取服务器端发的数据。道理同server端读数据一样:readBuffer(block,sizeof(block),不用重新组包。Top
3 楼helodd(感动/angle)回复于 2005-08-03 14:44:06 得分 10
支持上面说的Top
4 楼Idle_(阿呆)回复于 2005-08-03 20:22:41 得分 10
楼上的误人子弟啊.
当然会一次读到半个包或者读到多个包.
TCP连接不象UDP那样有边界检查, 可以保证你的读取到的是和对方发送数据包精确匹配的包.
而阻塞式TCP读取的返回条件也并不是一定要填满你指定长度的缓冲区才会返回. 它在将底层缓冲区中数据全部(或者尽可能多--假如你的读取缓冲放不下底层已收到的所有数据时)复制到你的读取缓冲区后就会返回, 而底层缓冲区中极有可能只有收到对方发送的一个庞大数据包的前一部分. 这种情况下当然只读到半个包.
同理, 底层缓冲区中可能已经有对方多次发送的数个小包了, 这种情况下你读到的当然就是多个包.Top
5 楼magc888(繁星)回复于 2005-08-04 09:29:56 得分 0
咳,越来越晕了。
经过实际的测试,服务端连续调用WriteBuffer,客户端使用多线程读连续的ReadBuffer,得到的数据包倒是比较规则,是不是可以认为出错的几率很小啊Top
6 楼Idle_(阿呆)回复于 2005-08-04 16:10:28 得分 0
"实际测试"? 本机(127.0.0.1)不算哦, 针对本机两个socket之间的通讯windows是特殊处理的, 通过类似共享内存实现数据传递的. 这种情况下连续发送和连续接收看上去收发的都是完整包并不能说明任何问题.Top
7 楼cyblueboy83(爱情白痴—电脑迷)回复于 2005-08-04 16:49:27 得分 0
学习
Top
8 楼mxj2000(小马)回复于 2005-08-05 17:14:43 得分 10
支持 Idle_(阿呆)Top
9 楼helodd(感动/angle)回复于 2005-08-06 13:52:14 得分 10
很高兴看到这样深入的理解. TCP是建立在连接的基础上的使用的,在底层当然可以任意的读取任意长度的接收到的内容. 在indy 的idtcpclient.readfuff(Abuff,Asize).是会自动的按顺序接收server端的发送内容并一一接收下来的,而不会在只接收到半个包而读取出来的.也不会因为多个数据包而没有保持数据的连续性. 也就是说在readbuff接收的数据是不再用重新组包的是有次序的. 而不像UDP那样读出来的包是没有任何次序的~
问题:是否只能不停的去掉用ReadBuffer过程,读出的数据是否要和串口通讯一样在去组包。 这样是可以的,不要再重新去组包~Top
10 楼halfdream(哈欠)回复于 2005-08-06 13:53:10 得分 5
INDY控件组实现得那么好的功能干嘛不用呢?
TIdTCPClient为什么不用readln呢?
ReadBuffer这样的功能,INDY本来就不该提供它.
Top
11 楼cjf1009(农民程序员)回复于 2005-08-06 14:40:55 得分 0
哈欠兄上面的话是什么意思?请详解Top
12 楼wizardqi(男巫)回复于 2005-08-08 10:10:03 得分 10
其实很简单嘛,只要双方遵从一个约定,即:每当发数据前都先发送本次发送数据的长度如:
TCPClient1.WriteInteger(DataLen);
TCPClient1.OpenWriteBuffer;
TCPClient1.WriteBuffer(Buffer,DataLen);
TCPClient1.CloseWriteBuffer;
而服务器端可以先读接收数据长度,再读数据如:
with AThread.Connection do
begin
DataLen:=ReadInteger;
ReadBuffer(Buffer,DataLen);
end;
Top
13 楼comanche(太可怕)回复于 2005-08-08 12:09:07 得分 10
晕~~~倒
支持 Idle_(阿呆), 可能会收到 2 个包, tcp 是流式协义, 流式是不分包的... tcp 还有个算法叫 nagle, 这个算法让数据到一定的尺寸再发送, 这个尺寸是 MTU, 一般啦宽带在 14xx 字节左右, 跟你的包是两回事. 用 tcp 这种协议发数据必要知道应收的尺寸或有结束符Top
14 楼magc888(繁星)回复于 2005-08-08 12:27:57 得分 0
大长见识了,继续讨论...Top
15 楼hangguojun(布丁)回复于 2005-08-08 12:33:15 得分 10
刚调试了IdUDPServer和IdUDPClient
对于IdUDPClient的数据接收问题:因为它没有IdUDPServer的OnUDPRead的类似功能
经我测试,放弃IdUDPClient
两端均可用IdUDPServer实现,这样就解决了数据不定时接收问题
我想TCP应该类似吧,希望对你有用Top
16 楼wizardqi(男巫)回复于 2005-08-08 14:44:35 得分 0
TCP协议的主要特征就是提供可靠的数据链路,能够保障数据串行无重复的收发,所以担心接收重复数据或者丢失数据实属杞人忧天。其实楼主要解决的主要问题就是双方都知道自己将要接收的数据长度,所以还是我所说的在发送前先发送即将发送的长度如:
with IdTCPClient1 do
begin
WriteInteger(DataLen);
OpenWriteBuffer;
WriteBuffer(Buffer,DataLen);
CloseWriteBuffer;
end;
接收方首先确定接收长度再接收数据如:
with AThread.Connection do
begin
DataLen:=ReadInteger;
ReadBuffer(Buffer,DataLen);
end;Top
17 楼2312(╰@oo恒星★)回复于 2005-08-08 15:24:54 得分 5
动手自己试试吧!
数据长度先发是一个办法Top
18 楼cjf1009(农民程序员)回复于 2005-08-08 15:45:42 得分 0
搂主问的是:“有没可能server端只读取了半个包,或者一次读取了2个包“
~~ ~~
而不是“是否收到”
~~
收到半个或一个是可能的,但ReadBuffer(Buffer,DataLen);是阻塞在那里的,收到半个包时不会向下运行;如果一次收到两个包,ReadBuffer(Buffer,DataLen);一次只读取一个包的内容,下次ReadBuffer时读剩下的一个包。Top




