关于UDP传输的结构体中string长度type
TxtData=record
cmd:string;
S:string;
end;xt:TxtData;IdUDPServer1.SendBuffer(serverIP,1001,xt,sizeof(xt));
谁能解决他的长度问题 不喜欢多包 不太容易控制 不喜欢规定他长度 最大254不够用 谁给个最佳解决方案
TxtData=record
cmd:string;
S:string;
end;xt:TxtData;IdUDPServer1.SendBuffer(serverIP,1001,xt,sizeof(xt));
谁能解决他的长度问题 不喜欢多包 不太容易控制 不喜欢规定他长度 最大254不够用 谁给个最佳解决方案
解决方案 »
- 版里有空的人, 去整理了一下LY主页的资料吧
- 继续问DCOM问题
- 请问一下,如何获得TShelllistview控件中,如何获得选择的所有文件名?
- 在程序里如何设置环境变量
- DELPHI爱好者的群1509183~~
- 如何使用 opendialog打开一个已经存在的数据表!
- 怎样解决程序运行时,都要跳出个连接数据库的对话框,每次都输入用户名和密码,很烦的!
- 注册组件为什么会出现如下错误?
- 十分急的问题。!!!
- access violation at address 0050978C in module 'coreide70.bpl'. Read of address
- 锁定DBgrid的前几列时,如何解决在左右移动时锁定列的列名不消失?
- 本人想聘请一个delphi家教
TxtData=record
cmd:array[1..24] of Char;
S:array[1..1024] of Char;
end;
type
TxtData=record
cmd:string;
S:string;
end; 只是需要自己写一个打包过程而已。function PackData(const Data: TxtData): string;
var
N1, N2: cardinal;
begin
N1 := Length(Data.cmd);
N2 := Length(Data.S);
SetLength(Result, SizeOf(N1) + N1 + SizeOf(N2) + N2);
move(N1, Result[1], SizeOf(N1));
move(TxtData.cmd[1], Result[SizeOf(N1) + 1], N1);
move(N2, Result[SizeOf(N1) + N1 + 1], SizeOf(N2));
move(TxtData.S[1], Result[SizeOf(N1) + N1 + SizeOf(N2) + 1], N2);
end;然后
IdUDPServer1.Send(serverIP,1001, PackData(xt)); 接收端需要一个解包过程,大同小异,你自己写吧。:)
如:
const
CMD_LOGIN = $00000001;
CMD_LOGOUT= $00000002;
...
type
TxtData=record
cmd: cardinal;
s: string;
end; function PackData(const Data: TxtData): string;
var
len: cardinal;
begin
len := Length(Data.s);
SetLength(Result,SizeOf(cardinal)+len);
move(Data.cmd,Result[1],SizeOf(cardinal));
move(len,Result[SizeOf(cardinal)+1],SizeOf(cardinal));
move(Data.cmd[1],Result[SizeOf(cardinal)*2+1,len);
end;
我是要SendBuffer一个包含N个String类型N(未知数)长度的结构体啊 不能局限在254啊
楼主提到的返回String并不是不能使用SendBuffer.
var
StrSend:String;
StrSend := PackData(xt);
SendBuffer(IP,
Port,
PChar(StrSend)(*这里面根据需要,具体看参数,如果不是PChar类型,而可以用PChar(StrSend)^或者StrSend[1]代替*),
Length(StrSend));
假设缓冲区的大小是1000个字节,连续发送每次300字节,第四次就只发出去了100字节.返回值就是100收的时候,可能收到了多个数据但只有一次Receive事件.至于最下层的发送分片是在读取了缓冲区后在发送时进行的,是更低层的驱动完成的.当然我们很多情况下发送时
for....
begin
send();
sleep(1000);
end这样完成的,要是将sleep去掉,有很大机率会出现一个Receive事件收到多个包和Send 时有部分数据没有发送.
Delphi的string可以存任意数据,最大可以到2GB(32-bit下),可以直接当buffer来使用。
TxtData=record
cmd:string;
S:string;
end; xt:TxtData; IdUDPServer1.SendBuffer(serverIP,1001,xt,sizeof(xt)); 大家别管UDP报最大多大 这个技术我有解决方案我问的是我的结构体中string不能固定再254 太小 不采用多包的情况下解决这个问题 记住是sendbuffer 别整到send(string)去 这个send是笨鸟才用的
send就是调用sendbuffer实现的,两者没有本质的区别。
你非要用sendbuffer,假设s是string,s[1]就是buffer的首地址。
不管你的结构多复杂,都可以打包到一个buffer中,至于这个buffer用string、array还是getmem一块空间,都是一回事,没有本质的区别。
你要实现不固定大小的动态结构,就肯定要采用类似的方法,就我所知,目前还没有哪种语言支持你想要的那种结构。
你既然“这么多经验”,连这么简单的问题都解决不了吗?:)
TxtData=record
cmd:string;
S:string;
end; xt:TxtData; IdUDPServer1.SendBuffer(serverIP,1001,xt,sizeof(xt));
String根本上来说只是一个指针,一个指针是4 个字节长度,所以你的 sizeof(xt)在32位的计算机上永远都是8SendBuffer 只是传递一个连接的内存块,不管你里面保存的是什么,当然要给定的是起始的位置和传递的字节数.String 是Delphi 自己定义的数据类型,而SOCKET通信都是接字节来传递的,所以要用SOCKET最好用字符串数组
如果你的接受端不是DELPHI开发的,最好在定义结构的时候加上Pack Record
用结构体来保存要传递的数据只是方便你赋值操作罢了,对于一些变长的传递会不好操作.最好的办法是用一个对象封装,TxtData=record
private
FID:String;
FTitle:String;
public function GetData(var AP:Pointer):Integer;
published
property ID:String read FID write FID;
property Title:String read FTitle write FTitle;
end;//得到值的指针和长度,注意,用完后要释放AP
function TxtData.GetData(var AP: Pointer): Integer;
var
ACMD:String;
AStr:String;
PInt:PInteger;
Len:Integer;
xd:TxtData;
begin
Len:=Length(FID)+Length(FTitle)+Sizeof(Integer)*3;
AP:=GetMemory(Len); PInt:=AP;
PInt^:=Len; //保存总长度 PInt:=Pointer(Integer(PInt)+Sizeof(Integer));
PInt^:=Length(FID); //保存第一个字符串长度 PInt:=Pointer(Integer(PInt)+Sizeof(Integer));
CopyMemory(PInt,@FID[1],Length(FID));//保存第一个字符串内容 PInt:=Pointer(Integer(PInt)+Length(FID));
PInt^:=Length(FTitle); //保存第二个字符串长度 PInt:=Pointer(Integer(PInt)+Sizeof(Integer));
CopyMemory(PInt,@FTitle[1],Length(FTitle));//保存第二个字符串内容 // FreeMemory(AP);
Result:=Len;
end;//从收到的值中恢复
procedure TxtData.SetData(const AP: Pointer; Len: Integer);
var
PInt:PInteger;
i:Integer;
xd:TxtData;
begin
PInt:=AP;
// Len:=Integer(PInt);
CopyMemory(@xd,AP,Len);
i:=PInteger(PInt)^;//得到总长度 PInt:=Pointer(Integer(PInt)+Sizeof(Integer));
i:=PInteger(PInt)^;//得到第一个字符串长度
SetLength(FID,i); PInt:=Pointer(Integer(PInt)+Sizeof(Integer));
CopyMemory(@FID[1],PInt,Length(FID));//得到第一个字符串内容
PInt:=Pointer(Integer(PInt)+Length(FID));
i:=PInteger(PInt)^;
SetLength(FTitle,i);//得到第二个字符串长度 PInt:=Pointer(Integer(PInt)+Sizeof(Integer));
CopyMemory(@FTitle[1],PInt,Length(FTitle));//得到第二个字符串内容
end;
从你9楼的发言你是个什么水平大家也都看出来了。
就你这种自以为是的态度+一个不开窍的榆木脑袋,你是彻底没前途的。
早告诉你了,结构中的成员要不固定大小和位置,只能先打包到一个buffer中再发送,至于这个buffer用string、array还是getmem一块空间,都是一回事,没有本质的区别。 没有你异想天开的那种自适应record类型。
听懂了没有?
真是个TMD毫无灵气、冥顽不化的笨鸟。:)
另,To ZyxIp,
在record中private是无效的,所有成员仍然能从外部直接访问。
就这个笨蛋的问题来看,除了在发送前动态建立结构,也没什么更好的办法,要不就是定义一个足够大的固定结构+压缩发送。
10楼都给你讲解了,你还是榆木脑袋死不开窍,是不是你妈怀孕的时候吃了死老鼠才生出你这么个钝胎来?
也不知道哪家倒霉的公司用你这种垃圾开发“通信产品”?
哈~~~哈~~~哈~~~哈~~~哈~~~
就算是不固定的结构也有办法
但是确实需要组织成String或者Stream
楼主出口成脏可不太好
不管怎么说人家也是帮你
TxtData=record
cmd:string[100]; //在这里定义长度。
S:string[100];
end; xt:TxtData; IdUDPServer1.SendBuffer(serverIP,1001,xt,sizeof(xt)); 这样就OK了
不定长度的record不是不可以发送,但是要自己处理下 SendBuff哪有这样的功能啊?
自己水平那么好为什么不用Socket API的.别人回答你的问题是看得起你,自己还在那里装大爷.
SendBuf发送的是什么?字符?数字?自己也不了解机制就瞎说,别人好象教你 你还整2B一个.
SendBuf是发送内容块里的内容 其中有个参数是指针头,另一个是偏移量.
SB.我实在看不下去了.record是一个知道结构指针和string一样.string是#0结尾的,record不是
如果你真的要发送这样的东西,你就要把record.String长度弄出来
好让Socket知道你要发送多长的东西.
SB.....