求教关于Socket通讯-----很急!(100分)

  • 主题发起人 主题发起人 terrace
  • 开始时间 开始时间
T

terrace

Unregistered / Unconfirmed
GUEST, unregistred user!
有这么个c语言定义的数据包结构用来在网络中发送:
struct pk
{
unsigned char a;
long b;
char c[5];
}

struct package
{
struct pk1 pk;//包控制信息
short d; //返回码
char e[1]; //传送的内容,从e开始为数据内容,实际使用时取其地址作为指针使用
}

怎么把上面的包结构翻译成Delphi语言的呀?尤其是char e[1],好象是动态的。不知道该怎么个用法。


各位大虾帮忙呀!!!!!
 
pk = packed record
a:byte;
b:longint;
c:array[0..4] of char;
end;
package = packed record
pk1:pk;
d:smallint;
e:array[0..0] of char;
end;
 
楼上朋友:
问题是char e[1]; //传送的内容,e[1]是动态的,比如我的包里要传送的内容是'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',那就是应该放在以e开始的地址中,具体该怎么使用呀?还有如何发包呀?怎么把这个package结构里面的内容都发出去呢?对方接收又该如何提取这个信息呢???
 
一个地址一个是4byte(一个long型)吧,一个byte是存放不了的。
var aa:string;
e := @aa;
 
楼上朋友:
我试了,不行,char e[1]是需要是动态的,因为从此地址开始存放了包的具体数据内容,例如可以任意对它付值'aaaaaaaaaaaa',用socket.sendbuf(package1,SizeOf(package1))发送后对方收不到package1.e地址开始的内容。 哪位大虾能帮忙给个发送和接收该结构的的具体代码呀??我很急着用,分不够还可以再加!!!!
 
Type
TBufferType=Array [1..1] of Byte;
PBufferType=^TBufferType;

DataBuf=Record
Size:LongWord;
Data:TBufferType;
End;



procedure SendQueue.SendBoth;
Var
s:LongWord;
DataStream:TWinSocketStream;
p,p1:^DataBuf;
Temp:Array[1..20*1024] of Byte;
begin
If NOT Terminated Then
Begin
If (FVideoQueue.Count>0) Then//AND (FAudioQueue.Count>0) Then
Begin
p:=FVideoQueue.Pop;
//p1:=FAudioQueue.Pop;
Try
If IsConnected Then
Begin
s:=p^.Size ;//+p1^.Size+8;
Move(p^,Temp,p^.Size+4);
//Move(p1^,Temp[P^.Size+4+1],p1^.Size+4);
//Combine data
DataStream:=TWinSocketStream.Create(ComSocket,100);
If DataStream.Write(s,4)=4 Then Datastream.Write(Temp,s);
DataStream.Free;
End;
Finally
FreeMem(p);
// FreeMem(p1);
End;
End;
End;
end;


procedure TMainForm.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
Var
p,p1:^DataBuf;
Temp:Array[1..20*1024] of Byte;
DataStream:TWinSocketStream;
s,s1:LongWord;
begin
If Socket.Connected Then
Begin
Try
DataStream:=TWinSocketStream.Create(Socket,1000);
Try
If DataStream.WaitForData(1000) Then
Begin
If DataStream.Read(s,4)=0 Then Socket.Close;
If DataStream.Read(Temp,s)=0 Then Socket.Close;
Move(Temp,s,4); //Size of the video block
If s<>0 Then
Begin
GetMem(p,s+4);
p^.Size:=s;
Move(Temp[5],p^.Data,s); //Data of the video block
CodedFrame1.Push(p);
VDC.Execute; //unpack
End;
{ Move(Temp[4+s+1],s1,4); //Size of the audio block
GetMem(p1,s1+4);
p1^.Size:=s1;
Move(Temp[4+s+4+1],p1^.Data,s1);
CodedAudio1.Push(p1);
ADC.Execute; //unpack}
End
Else
Socket.Close;
Finally
End;
Finally
DataStream.Free;
End;
End;
end;
够简单吧?!

 
楼上朋友:
谢谢你的回复,但我查了Delphi 的关于TWinSocketStream的help文档,有如下
Note: TWinSocketStream does not work with non-blocking sockets.
而我的通讯正好是non-blocking ,所以可能不能用TWinSocketStream,请问有什么流可以
用于non-blocking类型以及具体怎么发送和接收呢????

大虾请来帮忙呀!!!!
 
>比如我的包里要传送的内容是'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',那就是应该放在以e开始的地址中

lstrcpy( PChar(@myPackage.e),'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');

>还有如何发包呀?怎么把这个package结构里面的内容都发出去呢?
socket.sendbuf(package1,SizeOf(package1)+Length('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')-1)

 
注意myPackage不能用
var myPackage:package
定义
必须
type PPackage=^Package
var myPackage:PPackage

myPackage:=getmem(myPackage,sizeof(package)+Length('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'));
 
当然你不能到处都'aaaaaaaaaaaaaaaaaaaaaaaaaaa'
你要用一个变量 str:='aaaaaaaaaaaaaaaaaaaaaaaaaaa'
以后用str来表示 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
在lstrcpy那里还要用PChar(str)
 
非常感谢Pipi朋友,那么对于char e[1];该如何用Delphi语句写呢,为什么myPackage不能用var myPackage:package定义呢,还有用ReceiveBuf接收到的Package包是否先用Socket.ReceiveLength判断长度然后做提取?Socket通讯中ReceiveBuf发收一包的长度有限制吗?会不会造成接收方的数据包被割裂成两个包呢?
 
如何发送和数据如何打包没有关系,你当然也可以用sendbuf发送。
 
char e[1]
这样的结构成员在c是很常见的,主要用来放在最后、定义一个变长的成员
但是一般好的这种变长的结构,最前面应该有一个size成员指出实际的总的字节数

1、接收方的数据包被割裂成两个包是有可能的,特别是如果package很大
2、如果package很小,那么连续两个包合并成一个包送到,也是可能的
成熟的程序,应该是把接收到的内容先连起来,然后从包头判断起,如果内容够一个package就拷贝出来,如果还有剩下的内容,那么继续判断是不是够下一个pachage的长度……
 
Pipi朋友:
char e[1] 是否该写成Delphi 的 e:array[0..0] of char ?
为什么myPackage不能用var myPackage:package定义呢?
能给我一个成熟程序例子可以实现把接收到的内容先连起来,然后从包头判断起...吗?

谢谢!!!
 
> char e[1] 是否该写成Delphi 的 e:array[0..0] of char ?
是的。看下面的例子:

winbase.h里面有一个结构(注意最后一个成员):

typedef struct _COMMCONFIG {
DWORD dwSize; /* Size of the entire struct */
WORD wVersion; /* version of the structure */
WORD wReserved; /* alignment */
DCB dcb; /* device control block */
DWORD dwProviderSubType; /* ordinal value for identifying
provider-defined data structure format*/
DWORD dwProviderOffset; /* Specifies the offset of provider specific
data field in bytes from the start */
DWORD dwProviderSize; /* size of the provider-specific data field */
WCHAR wcProviderData[1]; /* provider-specific data */
} COMMCONFIG,*LPCOMMCONFIG;

对应windows.pas里面:

_COMMCONFIG = record
dwSize: DWORD;
wVersion: Word;
wReserved: Word;
dcb: TDCB;
dwProviderSubType: DWORD;
dwProviderOffset: DWORD;
dwProviderSize: DWORD;
wcProviderData: array[0..0] of WCHAR;
end;
 
>为什么myPackage不能用var myPackage:package定义呢
因为最后一个成员e它实际不是1个字节,如果用var myPackage:package
那么myPackage的内存,e只分配了定义的1个字节,如果你往e写了很多字节,就会缓冲区溢出,破坏了堆栈,引起莫名其妙的错误
 
>能给我一个成熟程序例子可以实现把接收到的内容先连起来,然后从包头判断起...
暂时还找不到
 
Pipi朋友:
你说,往e写了很多字节,就会缓冲区溢出,破坏了堆栈,你所说的缓冲区是指栈吧,因为用var myPackage:package定义的变量是在栈中分配的,那么栈的最大容量是多少呢,用指针var myPackage:package^ 定义的变量应该是在堆中分配的,那么堆的最大容量又是多少呢?
 
堆和栈都很大,堆和本机内存有关,栈和连接的设置有关(看project options),缺省也有10M
缓冲区溢出是指“e”溢出,不是指栈不够大
因为堆栈里面各个变量、各个值是前后排列在一起的,
用 var myPackage:package ,堆栈里面只给了e一个字节的空间,后面就会安排其他变量或者其他内容的使用
如果你往e这个地址写了很多字节,那么实际上他覆盖了他后面的别的变量
如果你又调用了其他过程,参数入栈、返回地址入栈的时候也可能会覆盖掉e
 
可以结贴了,谢谢Pipi朋友!
 
后退
顶部