idtcpclient和idtcpserver控件使用时的问题(100分)

  • 主题发起人 andywang
  • 开始时间
A

andywang

Unregistered / Unconfirmed
GUEST, unregistred user!
各位朋友:
我有一段代码是这样实现的。
//首先是定义一个协议
TTransRec = record
TRType: (ttConnected, ttData, ttDataEnd, ttDisconnect);
DataSize: Int64;
Data: Pointer;
end;

在客户端
点击连接按钮时:idtcpclient.connect;
点击发送文件按钮时:
var
FFileStream: TFileStream;
SendBuf: TTransRec;
pPointer: Pointer;

sFileName: string;
begin
try
sFileName := 'D:/1.txt';
//这里为了简单,直接指定了一个文件,它的内容是:123456
FFileStream := TFileStream.Create(FFileDir, fmOpenRead);
GetMem(tmpPointer, FFileStream.Size);
FFileStream.ReadBuffer(tmpPointer^, FFileStream.Size);
SendBuf.TransType := ttData;
SendBuf.DataSize := FFileStream.Size;
SendBuf.Data := tmpPointer;
IdTCPClient.WriteBuffer(SendBuf, SizeOf(SendBuf));
finally
FreeAndNil(FFileStream);
FreeMem(tmpPointer);
end;
end;

在服务器端:
idTCPServer的OnExecute事件中写:
var
RecieveBuf: TTransRec;
pPointer: Pointer;
FFileStream: TFileStream;
begin
try
AThread.Connection.ReadBuffer(RecieveBuf, SizeOf(RecieveBuf));
//这里的SizeOf(RecieveBuf)
if RecieveBuf.TRType = ttData then
begin
FFileStream := TFileStream.Create('E:/1.txt', fmOpenWrite);
pPointer := RecieveBuf.Data;
FFileStream.WriteBuffer(pPointer^, RecieveBuf.DataSize);
//这里的SizeOf(pPointer)
end;
finally
FreeAndNil(FFileStream);
end;
end;

但是我在运行时,保存的文件内容跟发送的文件内容不一致。
哪位兄弟有这方面的Demo,请发一份给我,或是指点一二,小弟感激不尽。
 
IdTCPClient.WriteBuffer(SendBuf, SizeOf(SendBuf));
你这个sizeof,你以为它的大小,对吗?????
还有AThread.Connection.ReadBuffer(RecieveBuf, SizeOf(RecieveBuf));
//这里的SizeOf(RecieveBuf)
对吗????????????????
 
TO: qnaqbgss
SizeOf()返回的变量类型的大小。
像这种情况是不是不能这样定义包的结构?昨天有看到些资料,照他的作法是先发送一个Int64型的数过去,表示大小。
var
pPointer: Pointer;
fFileStream: TFileStream;
iFileSize: Int64;
begin
idTcpClient.Connect;
fFileStream := TFileStream.Create('D:/1.txt', fmOpenRead);
iFileSize := fFileStream.Size;
idTcpClient.WriteIntege(iFileSize);
pPointer := AllocMem(iFileSize);
fFileStream.ReadBuf(pPointer, iFileSize);
idTcpClient.WriteBuf(pPointer, iFileSize);
idTcpClient.Disconnect;
end;

服务器端:
var
iRecieve: Int64;
pRecieve: Pointer;
begin
if AThread.Connection.Connected then
begin
iRecieve := Athread.Connection.ReadInteger;
pRecieve := AllocMem(iRecieve);
AThread.Connection.ReadBuf(pRecieve, iRecieve);
end;
end;

我就是不想分二次这样发送。想把它定义到一个包中发送,所以我才想到要定义一个Record,但是这样发送不知道要怎么实现。
请问你一般都是怎么实现的?
 
PTransRec = ^TTransRec;
TTransRec = record
TRType: (ttConnected, ttData, ttDataEnd, ttDisconnect);
DataSize: Int64;
end;

在客户端
点击连接按钮时:idtcpclient.connect;
点击发送文件按钮时:
var
FFileStream: TFileStream;
SendBuf: TTransRec;
pPointer: Pointer;

sFileName: string;
begin
try
sFileName := 'D:/1.txt';
//这里为了简单,直接指定了一个文件,它的内容是:123456
FFileStream := TFileStream.Create(FFileDir, fmOpenRead);
GetMem(tmpPointer, FFileStream.Size+SizeOf(SendBuf));
PTransRec(tmpPointer).TransType := ttData;
PTransRec(tmpPointer).DataSize := FFileStream.Size;
FFileStream.ReadBuffer(Pointer(Integer(tmpPointer)+SizeOf(SendBuf))^, FFileStream.Size);
IdTCPClient.WriteBuffer(tmpPointer^,FFileStream.Size+SizeOf(SendBuf));
finally
FreeAndNil(FFileStream);
FreeMem(tmpPointer);
end;
end;

TCP是面向流的协议,数据包是粘连在一起的。你分批次发送的数据也可能只一次调用就接收,一次发送的数据也可能被多次调用分批次接收。你非要一个Send发出,就用上面的办法。你原来的做法发送一个指针给对方有个屁用。通讯两端都是同一进程还没事,要是不同进程,接收方访问这个地址还能引起access violation。另外TCP要中断就直接IdTcpClient.Disconnect就行了,另一端会知道连接中断。把连接和断开做进你的自定协议根本就是脱了裤子放屁多此一举。
 
顶部