首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

TCP通讯时,发送缓冲区用结构体表示,结构体中定义的变量能否不固定大小

2013-09-05 
TCP通信时,发送缓冲区用结构体表示,结构体中定义的变量能否不固定大小.如题目的意思如果没清楚意思,看下面

TCP通信时,发送缓冲区用结构体表示,结构体中定义的变量能否不固定大小.
如题目的意思
如果没清楚意思,看下面代码


定义了一个公共模块,客户端和服务端程序都引用他



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;
implementation

end.






然后在客户端对这个结构进行赋值并发送

//向服务端发送登录请求返回通信命令协议加密串,使得软件和以和服务端交互
  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直接传入到处理函数去呢? 
传入指针我最终还是要转成结构的啊..
结构体 内存 分配 缓冲区 通信
[解决办法]
你自己已经想到了呀!  

TCommBlock = packed  record   
                 Command,
                 MyUserName,                 
                 Msg,                        


                 ReceiverName: string[100];  
                 cid:integer;  
                 loginflag:Boolean;
                 usernameLen:int; //UserName对应的字符串的长度    
                 passwordLen:int; //Password对应的字符串的长度
               end;
写完Block后再写入UserName和Password两个字符串
读取的时候先读取Block获取两个字符串的长度,然后从流中按取得的长度分别读取UserName和Password两个字符串
[解决办法]
你这里结构体里面不能有不定长度的类型,如string
不定长一定要改为定长,否则你不要用结构体,改为XML或JSON封装,然后传一个封装完的长string,用buff+size方式传递
[解决办法]
二进制格式,运行效率最高,空间效率一般(部分域因为按最大空间预留,也可能浪费),但是最不灵活
现在应该采用灵活的xml/json/ini作为数据表达协议,只要效率限制允许
[解决办法]
介于二进制结构和xml/json/ini之间,还有一种协议:
tlv(tag-length-value)
[解决办法]
不能。              。
[解决办法]
每块是定长,但是块数可变
[解决办法]

引用:
我根据块数的多少来接受这样行吗   难道要一块一块接受?
不能一次接受几块吗?


可以啊

理论上只需要接收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;
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;



这样算是定长的缓冲区块的接受吗  是缓冲区的问题还是我程序其他地方的问题?



定义结构体,
//单条订单的结构    
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;...
试试
[解决办法]
到Torry下载个JDSockets,省了造轮子的麻烦

热点排行