Record中使用长String问题(Indy中):(100分)

  • 主题发起人 主题发起人 liuchong
  • 开始时间 开始时间
L

liuchong

Unregistered / Unconfirmed
GUEST, unregistred user!
发送端正常:
type
MyRec=record
Length:Word;
S:string;
end;

procedure TForm1.btn1Click(Sender: TObject);
var
R,M:MyRec;
begin
R.S:=Edit1.Text;
R.Length:=Length(R.S);
idUDPServer1.SendBuffer('192.168.0.3',8001,R,SizeOf(R));
end;
//接收端出错:

type
MyRec=record
Length:Word;
S:string;
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
R:MyRec;
begin
SetLength(R.S,AData.Size-3);
AData.ReadBuffer(R,AData.Size);
Caption:=R.S;//不能正常得到结果
end;
 
修改
AData.ReadBuffer(R,AData.Size);
成为
AData.ReadBuffer(R,sizeof(R));
试一试
 
string在内存中都是指针,指向一个内存管理器管理的地址,所以,你的MyRec传送过去后,得到的指针无法在接收端被读取,因为指向的地址可能存有任何数据。所以,改成下面这样就可以了:
type
MyRec=record
Length:Word;
S:ShortSTring;//ShortString是固定长度的字符串,等于array [0..255] of Char;
end;
 
如果想传长串,怎么办呢?
 
通用的办法:先传递数据包的长度,再传递包内容。多长都没有问题
 
按你的record; 这是发送(已修改): 未调试,你试试吧。
procedure TForm1.btn1Click(Sender: TObject);
var
R,M:MyRec;
buf:pchar;
buf_len:Dword;
begin
R.S:=Edit1.Text;
R.Length:=Length(R.S);
buf_len:=sizeof(r.length)+ Length(r.S));
buf:=allocMem(buf_len);
move(r.length,buf[0]^,sizeof(r.length);
move(r.s[1],buf[sizeof(r.length)]^,length(r.s));
idUDPServer1.SendBuffer('192.168.0.3',8001,buf,buf_len);
freemem(buf,buf_len);
end;

接收:
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
R:MyRec;
buf,buf2:pchar;
buf_len:Dword;
begin
buf_len:=AData.Size;
allocmem(buf,buf_len);
AData.ReadBuffer(buf,buf_len);
r.length:=Word(buf^);
buf2:=pchar(integer(buf)+Sizeof(r.Length));
r.s:=buf2;
freemem(buf,buf_len);
//下面正常使用R
Caption:=R.S;//不能正常得到结果

end;
 
测试失败
 
最好不要在发送的数据结构中使用String类型,因为String是不受控制的,接受方很容易出现乱码的情况。
关于在传输过程中想传长串的问题,可以用Byte数组解决
MyRec= packed record
Length:Word;
S:array[0..1000] of byte;//具体长度自己定,但是不要超出定义的数据包的长度
end;

发送时:
var
MyRecord : MyRec

StrPCopy(@MyRecord.S,'abcdefghigidasklfjdakf;kfjda;f');
接收时
var
myStr : String;

myStr := StrPas(@MyRecord.s);
 
我的代码编译不过去,你能否把你的测试代码给我,我给你调试好了。
 
to:chchao1980就是要动态设置长度的啊,不想在定义时确定
to:shangshang
代码如下:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdUDPBase, IdUDPServer,IdSocketHandle;

type
TForm1 = class(TForm)
IdUDPServer1: TIdUDPServer;
btn1: TButton;
Edit1: TEdit;
procedure btn1Click(Sender: TObject);
procedure IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

type
MyRec=record
Length:Word;
S:string;
end;

procedure TForm1.btn1Click(Sender: TObject);
var
R:MyRec;
begin
R.S:=Edit1.Text;
R.Length:=Length(R.S);
idUDPServer1.SendBuffer('192.168.0.3',8001,R,SizeOf(R));
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
R:MyRec;
begin
SetLength(R.S,AData.Size-3);
AData.ReadBuffer(R,AData.Size);
Caption:=R.S;//不能正常得到结果
end;

end.
 
我觉得你的代码可能是使用string的方法有点问题,可以修改如下:
发送端正常:
type
MyRec=record
Length:Word;
S:string;
end;

procedure TForm1.btn1Click(Sender: TObject);
var
R,M:MyRec;
begin
R.S:=Edit1.Text;
R.Length:=Length(R.S);
//修改
idUDPServer1.SendBuffer('192.168.0.3',8001,R.S[1],R.Length);
end;
//接收端出错:

type
MyRec=record
Length:Word;
S:string;
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
R:MyRec;
begin
//修改
SetLength(R.S,AData.Size);
AData.ReadBuffer(R.S[1],AData.Size);
Caption:=R.S;//不能正常得到结果
end;
 
要是记录中不只要传送String,还有别的数据呢
 
另外:我记得窗口的Caption应该有长度限制的,好像255吧,先发给短试试吧,可以把内容付给Memo试一下
 
其实String是个很好的Buffer,可以放任何数据,我就在String中放图片,关键是解析的问题了
 
那你可以使用动态array of byte数组
 
同意chchao1980,我也用array of char

type
MyRec=record
Length:Word;
S:array[0..65535] of char;
end;
这样就可以传递64k的String了。
 
type
MyRec=record
Length:Word;
S:string;
end;
用 string 也可以
type
MyRec=record
Length:Word;
S:string[1000];
end;
 
没有必要用长 string,
如果你定义了 string[1000], buffer 就很大,有时候你发送 两个字符,也用 1000的buffer?
应该分开,
buffer头 写上 s 的长度, 后面部分 写入 s 的内容, 这才是正确 做法, 当然,如果你的包包含其他信息, 你也可以定义一个 Record,将Record 放在 buffer 的 开头,接着添加 s 的内容 到 buffer 后面。 发送, 收取后 反过来 读出 buffer。
 
昨天没调好,今天给你吧。用string也行,反正都是麻烦

implementation


type
MyRec = record
Length: Word;
S: string;
end;
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
R: MyRec;
buf: array of char;
buf_len: Dword;
begin
R.S := Edit1.Text;
R.Length := Length(R.S);
buf_len := sizeof(r.length) + Length(r.S) + 1;
SetLength(buf, buf_len);
move(r.length, buf[0], sizeof(r.length));
move(r.s[1], buf[sizeof(r.length)], length(r.s));
idUDPServer1.SendBuffer('127.0.0.1', 8001,buf[0], buf_len);
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
R: MyRec;
buf: array of char;
buf_len: DWORD;
begin
buf_len := AData.Size;
setlength(buf, buf_len);
AData.ReadBuffer(buf[0], buf_len);
Move(buf, r.length, sizeof(r.length));
r.s := PChar(@buf[sizeof(r.length)]);
caption := r.s;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
IdUDPServer1.Active:=True;
end;

end.
 
客户端:
type
WordStr=string[2];

type
MyRec=record
Length:Word;
S:string;
end;

function WordToStr(const Value: Word): WordStr;
begin
SetLength(Result, SizeOf(Value));
Move(Value, Result[1], SizeOf(Value));
end;

function Packet(R:MyRec):string;
begin
Result:=WordToStr(Length(R.S))+R.S;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
R:MyRec;
tmp:string;
begin
R.S:=Edit1.Text;
R.Length:=Length(R.S);
tmp:=Packet(R);
IdUDPServer1.SendBuffer('192.168.1.26',5555,tmp[1],Length(tmp));
end;

服务器端:
type
WordStr=string[2];

type
MyRec=record
Length:Word;
S:string;
end;

function StrToWord(const Value: String): Word;
begin
Result := PWord(@Value[1])^;
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
R:MyRec;
tmp:string;
begin
SetLength(tmp,2);
AData.ReadBuffer(tmp[1],2);
R.Length:=StrToWord(tmp);
SetLength(R.S,R.Length);
AData.ReadBuffer(R.S[1],R.Length);
Caption:=R.S;
end;
 
后退
顶部