delphi中clientsocket接收数据是不是有问题????

lonelylight 2003-02-26 03:48:13
我用delphi的clientsocket.recievebuf 取数据的时候发现serversocket.socket.sendbuf 发出来的数据和客户端接收的数据量不等。
我在server端一共发送了9708个字节。但是接收端一共接收到两次,显示出信息如下:
recieve len:=8192
recieve len:=2408
总共接收到了 10600个字节。
尝试了很多次,都是这样子。百思不得不得其解。
请相关高手不吝赐教!
...全文
647 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
halfdream 2003-03-07
  • 打赏
  • 举报
回复
另一方面,确定你发送端确实发了多少字节.

贴出一个我才写的,调试了一下的.
//--------------------------------------------------------
type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure Button1Click(Sender: TObject);
procedure ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
FStr:String;
Fo:TStream;
procedure DisplayMsg(s:string);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
s:string;
iSize:Integer;
begin
FSTr:='';
SetLength(s,3);//这是故意设置这么短的,有问题则更容易暴露
repeat
iSize:=Socket.ReceiveBuf(pchar(s)^,3);
if iSize>0 then
begin
SetLength(s,iSize);
Fo.Write(pchar(s)^,iSize);
FStr:=FSTr+s;
end
until (iSize<>3) or (iSize=-1);
DisplayMsg(FStr);
end;

procedure TForm1.DisplayMsg(s: string);
begin
memo1.Lines.Add(s)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Active:=true;
end;

procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Fo:=TFileStream.Create('d:\test.txt',FmCreate);
end;

procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Fo.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ClientSocket1.Active:=false;
end;

end.
lonelylight 2003-03-07
  • 打赏
  • 举报
回复
我的问题的关键是 为什么发了9708个字节,但是收到的却多于9708个字节。
halfdream 2003-03-07
  • 打赏
  • 举报
回复
其实不该说多了,
你的关键问题就在使用了len:=Self.Socket.ReceiveLength;
halfdream 2003-03-07
  • 打赏
  • 举报
回复
什么winsocket的线程机制,在同步处理的时候才要考虑多线程.
在异步非阻塞WINSOCKET中,这些事件统统都是在 主 线 程 触 发 的,
这一点一定要清楚.
也许上面具体程序没有调试过,并不等于解决不了问题.




lonelylight 2003-03-06
  • 打赏
  • 举报
回复
以上方法依然不通,问题是你还没了解winsocket的线程机制。如果再触发一次onread而
while还没有循环完,那岂不是乱了。我试过了,不行。不过谢谢你。
lonelylight 2003-03-01
  • 打赏
  • 举报
回复
以上方法不通。
halfdream 2003-03-01
  • 打赏
  • 举报
回复
呵,没仔细看,确实写错了。。

iSize:=Socket.ReceiveBuf(pchar(sBuf)^,2000);
if(iSize>0) fo.Write(pchar(sBuf)^,iSize)
while (iSize=2000) do
begin
iSize:=Socket.ReceiveBuf(pchar(sBuf)^,2000);
if(iSize>0) fo.Write(pchar(sBuf)^,iSize)
end;
halfdream 2003-03-01
  • 打赏
  • 举报
回复
拜托,你说清楚点,辛苦敲了这么半天字,你总不能一个不通就了事。。
上面列出的代码只是写出来示意。 类似的这样思路代码我实际用过来传大文件也无问题,
当然,也许可以补上一些处理消息的代码,但那已无关紧要。



halfdream 2003-02-27
  • 打赏
  • 举报
回复
说清楚你具体的做法吧.最好贴出源码.

不管直接使用SOCKET API还是组件本质都是一样的.

发送的时候,SENDBUF会访回实际发出的字节数.

至于接收,使用TClientSocket你的具体做法是什么?
你好象是用的非阻塞方式,
如果是阻塞方式,接收数据最好用TWinSocketStream.


lonelylight 2003-02-27
  • 打赏
  • 举报
回复
我使用过了很多种方法,
第一种 将 9708个字节以1024个字节为一个包发送。
第二种 将9708个字节全部以一个包的形式发送。
第三种 调用winsocket2 API 中的TransmitFile函数一下子将文件发送出去。
第四种 调用底层API重新改写第一种、第二种两种方式。
最后测试的结果类似。
所有的错误都是在8192个字节后多了很多字节。现在是传9708个字节。我尝试了一下,传送大一点的数据,错误可能更多。

halfdream 2003-02-27
  • 打赏
  • 举报
回复
大致做法是这样的...细节你自己想吧.

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
sBuf:string; //用STRING只是因为我熟悉它.
iSize:integer;
fo:TMemoryStream;
begin

fo:=TMemoryStream.Create;
SetLength(sBuf,2000);

iSize:=Socket.ReceiveBuf(pchar(sBuf)^,2000);
while iSize>0 do
begin
fo.Write(pchar(sBuf)^,iSize)
end;
.....


end;
lonelylight 2003-02-27
  • 打赏
  • 举报
回复
我在什么地方进行这个循环。(在一个WHILE循环中ReceiveBuf,直到没有数据读出。)
halfdream 2003-02-27
  • 打赏
  • 举报
回复
buf 你可以设固定长度,

在一个WHILE循环中ReceiveBuf,直到没有数据读出。
halfdream 2003-02-27
  • 打赏
  • 举报
回复
//问题是出在这儿:
//在帮助上面也提到过,用Receivelength并不能精确取得实际读到的数据长度。
len:=Socket.ReceiveLength;

//应该判断这儿函数的返回值,才是真正有效读到的。
len:=Socket.ReceiveBuf(buf^,len);

lonelylight 2003-02-27
  • 打赏
  • 举报
回复
以上是我接收部分的原码
lonelylight 2003-02-27
  • 打赏
  • 举报
回复
clientsocket.onread事件
var
len:integer;
buf:pbyte;
bufcheck:pbyte;
begin
len:=Self.Socket.ReceiveLength;
memo1.lines.add('recieved'+inttostr(len));
buf:=GetMemory(len);
bufcheck:=GetMemory(14);
ZeroMemory(bufcheck,14);
ZeroMemory(buf,len);
self.Socket.ReceiveBuf(buf^,len);
CopyMemory(bufcheck,ptr(integer(@(buf^))+(len-13)),13);
if pchar(bufcheck)='SendFError_FT' then
begin
Freemem(buf);
FreeMem(bufcheck);
Self.Close;
Self.Open;
exit;
end;
if pchar(bufcheck)='SendFinish_FT' then
begin
memstream.Write(buf^,len-13);
memo1.lines.add('alllength=',inttostr(memstream.size));
FreeMem(buf);
FreeMem(bufcheck);
self.Close;
Self.Destroy;
Exit;
end;
memstream.Write(buf^,len);
FreeMem(buf);
FreeMem(bufcheck);

其中memstream为全局 Tmemorystream
halfdream 2003-02-26
  • 打赏
  • 举报
回复
一个TCP连接的两站,不管你发送端怎么发,每次多少字节,发多少次,
接收方的接收只管在一个数据流中读,同发送端动作无关。

因此,需要自己在这个SOCKET数据流里面用一定办法来同步两端动作。
比如HTTP是发串数据,使用的是两个回车换行同步。
RPC是发块数据,在块指定字段定义了块长度。。
wisenowa 2003-02-26
  • 打赏
  • 举报
回复
该接收多少就接收多少,

用SocketAPI写,非常好
lonelylight 2003-02-26
  • 打赏
  • 举报
回复
老兄,现在不是没有接收完,是多接收了。怎么办啊。
wisenowa 2003-02-26
  • 打赏
  • 举报
回复
那是你还没有接受完

你可以在发送前先发送要发送的数据大小

而接受时直到接受够大小放罢休。

1,593

社区成员

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

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