如题目的意思
如果没清楚意思,看下面代码
定义了一个公共模块,客户端和服务端程序都引用他unit GlobalUnit;interface
type
PCommBlock = ^TCommBlock; //自定义了一个结构体指针TCommBlock
TCommBlock = packed record // the Communication Block used in both parts (Server+Client)
Command,
MyUserName, // the sender of the message (by DNS name)
Msg, // the message itself
ReceiverName: string[100]; // name of receiver //信息不能超过100字符大小是硬伤 这样传输效率明显不高
cid:integer; //用来确定反馈信息在哪输出的
loginflag:Boolean;
username:string; //不规定大小的情况缓冲区的大小会变化 sizeof没有结果 不知道delphi内存怎么分配结构体内存的
password:string; //发送的时候给了值 可以得到大小 接受的时候没有合适的大小去匹配
end;
implementationend.
然后在客户端对这个结构进行赋值并发送//向服务端发送登录请求返回通信命令协议加密串,使得软件和以和服务端交互
CommBlock.Command := 'Login'; // assign the data
CommBlock.MyUserName := Client.LocalName;
CommBlock.Msg := 'login test';//可以自定义协议串 或者用二进制数据传输一个结构体 需要定义一个完善的命令协议
CommBlock.ReceiverName := '';
CommBlock.username :='admin';
CommBlock.password :='xxx';Client.WriteBuffer (CommBlock, SizeOf (CommBlock), true);
服务端接受缓冲区的内容
AThread.Connection.ReadBuffer (CommBlock, SizeOf (CommBlock));//执行到这里就出错
command_do(CommBlock,Protocol,Clients);//这是自定义的函数用来处理命令的
这样做的话ReadBuffer的时候 写入CommBlock的时候就出错 这我能理解 到服务端的时候CommBlock中的username password等没有赋值 计算出来的大小不知道delphi怎么算的 CommBlock大小可能不够大放不下发过来的东西然后我就想到一个办法在客户端发送的时候//在这里先发送CommBlock的大小
length:=SizeOf (CommBlock);
Client.WriteBuffer (length, 4, true);
Client.WriteBuffer (CommBlock, SizeOf (CommBlock), true);服务端接受的时候var
m_PCommBlock:PCommBlock;
begin
//略.......
//先读出CommBlock的大小 再给CommBlock的指针m_PCommBlock分配内存
AThread.Connection.ReadBuffer (buffersize, 4);
GetMem(m_PCommBlock,buffersize); //分配内存
CommBlock :=m_PCommBlock^;//在这里加入赋值来测试结果 发现在这里就出错了
//仔细想想也是不行 CommBlock依然是大小不对的吧
AThread.Connection.ReadBuffer (m_PCommBlock^, buffersize);
//然后读入到m_PCommBlock这也不行?end;仔细想想也是不行 CommBlock依然是大小不对的吧要怎么写才能申明一个结构大小都正确CommBlock直接传入到处理函数去呢?
传入指针我最终还是要转成结构的啊..
结构体内存分配缓冲区通信
如果没清楚意思,看下面代码
定义了一个公共模块,客户端和服务端程序都引用他unit GlobalUnit;interface
type
PCommBlock = ^TCommBlock; //自定义了一个结构体指针TCommBlock
TCommBlock = packed record // the Communication Block used in both parts (Server+Client)
Command,
MyUserName, // the sender of the message (by DNS name)
Msg, // the message itself
ReceiverName: string[100]; // name of receiver //信息不能超过100字符大小是硬伤 这样传输效率明显不高
cid:integer; //用来确定反馈信息在哪输出的
loginflag:Boolean;
username:string; //不规定大小的情况缓冲区的大小会变化 sizeof没有结果 不知道delphi内存怎么分配结构体内存的
password:string; //发送的时候给了值 可以得到大小 接受的时候没有合适的大小去匹配
end;
implementationend.
然后在客户端对这个结构进行赋值并发送//向服务端发送登录请求返回通信命令协议加密串,使得软件和以和服务端交互
CommBlock.Command := 'Login'; // assign the data
CommBlock.MyUserName := Client.LocalName;
CommBlock.Msg := 'login test';//可以自定义协议串 或者用二进制数据传输一个结构体 需要定义一个完善的命令协议
CommBlock.ReceiverName := '';
CommBlock.username :='admin';
CommBlock.password :='xxx';Client.WriteBuffer (CommBlock, SizeOf (CommBlock), true);
服务端接受缓冲区的内容
AThread.Connection.ReadBuffer (CommBlock, SizeOf (CommBlock));//执行到这里就出错
command_do(CommBlock,Protocol,Clients);//这是自定义的函数用来处理命令的
这样做的话ReadBuffer的时候 写入CommBlock的时候就出错 这我能理解 到服务端的时候CommBlock中的username password等没有赋值 计算出来的大小不知道delphi怎么算的 CommBlock大小可能不够大放不下发过来的东西然后我就想到一个办法在客户端发送的时候//在这里先发送CommBlock的大小
length:=SizeOf (CommBlock);
Client.WriteBuffer (length, 4, true);
Client.WriteBuffer (CommBlock, SizeOf (CommBlock), true);服务端接受的时候var
m_PCommBlock:PCommBlock;
begin
//略.......
//先读出CommBlock的大小 再给CommBlock的指针m_PCommBlock分配内存
AThread.Connection.ReadBuffer (buffersize, 4);
GetMem(m_PCommBlock,buffersize); //分配内存
CommBlock :=m_PCommBlock^;//在这里加入赋值来测试结果 发现在这里就出错了
//仔细想想也是不行 CommBlock依然是大小不对的吧
AThread.Connection.ReadBuffer (m_PCommBlock^, buffersize);
//然后读入到m_PCommBlock这也不行?end;仔细想想也是不行 CommBlock依然是大小不对的吧要怎么写才能申明一个结构大小都正确CommBlock直接传入到处理函数去呢?
传入指针我最终还是要转成结构的啊..
结构体内存分配缓冲区通信
Command,
MyUserName,
Msg,
ReceiverName: string[100];
cid:integer;
loginflag:Boolean;
usernameLen:int; //UserName对应的字符串的长度
passwordLen:int; //Password对应的字符串的长度
end;
写完Block后再写入UserName和Password两个字符串
读取的时候先读取Block获取两个字符串的长度,然后从流中按取得的长度分别读取UserName和Password两个字符串
不定长一定要改为定长,否则你不要用结构体,改为XML或JSON封装,然后传一个封装完的长string,用buff+size方式传递
现在应该采用灵活的xml/json/ini作为数据表达协议,只要效率限制允许
tlv(tag-length-value)
POrderBlock = ^OrderBlock;
OrderBlock = packed record
caption:string[10];
username:string[50];
address:string[255];
tel:string[50];
end;
OrderListBlock = array of OrderBlock; //用这个动态数组来保存这个定长的结构体
发送的时候//block是OrderListBlock类型的变量 先用setlength设置过数组长度 并给过初始值
l:=Length(block);
RecThread.Connection.WriteBuffer(l,4, True); // 先把大小发过去
RecThread.Connection.WriteBuffer(block, SizeOf(block), True); // 再发内容
接受的时候 //m_block 是OrderListBlock类型的变量
try
Client.ReadBuffer(l, 4);
SetLength(m_block,l);
buf_size :=l*SizeOf(OrderBlock);
showmessage(IntToStr(buf_size));//这里是缓冲区大小
showmessage(IntToStr(sizeof(m_block))); //这里显示的是数组元素的个数
Client.ReadBuffer(m_block, l*SizeOf(OrderBlock));//执行到这句 程序就死了 调试器也没报异常 显示程序正在运行 但是程序是死的 在任务栏点选程序界面都出不来 令一端是服务端显示客户端连接丢失了.. PostMessage(main_form_handle, WM_updateOrderList, 0, 0); //发送消息更新界面
except
showmessage(IntToStr(buf_size));
end;这样算是定长的缓冲区块的接受吗 是缓冲区的问题还是我程序其他地方的问题?
可以啊理论上只需要接收2次:
1、接收 块数n
分配好足够的空间 setlength(字节可变数组. n*sizeof(record));
或setlength(record可变数组. n);
2、接收 所有块n*sizeof(record)字节到对应的数组只是实际上,后面的数据可能不是一次性到达的
不过,如果指定了读满n*sizeof(record)为止的话,它会一直读够才返回
//单条订单的结构
POrderBlock = ^OrderBlock;
OrderBlock = packed record
caption:string[10];
username:string[50];
address:string[255];
tel:string[50];
end;
变成:caption :array[0..9] of char;
username :array[0..49] of char;...
试试