网络高手看过来:为什么我用htons转换网络节序时会发生错误?200元大洋伺候(200分)

  • 主题发起人 主题发起人 youjq
  • 开始时间 开始时间
Y

youjq

Unregistered / Unconfirmed
GUEST, unregistred user!
procedure TForm1.Button1Click(Sender: TObject);
type TDebugDL = record
Parm1:String;
Parm2:String;
Parm3:String;
Parm4:String;
Parm5:String;
Parm6:String;
Parm7:String;
end;
var
FSyn_Buf: array[0..2] of char;
TheStream: TWinSocketStream;
ClientSocket: TClientSocket;
iPkglen: integer;
iTotalPkg: Word;
DebugDL: TDebugDL;
begin
DebugDL.Parm1:=Format('%-6s',['010200']);
DebugDL.Parm2:=Format('%-6s',['335615']);
DebugDL.Parm3:=Format('%-10s',['100120130']);
DebugDL.Parm4:=Format('%-8s',['']);
DebugDL.Parm5:=Format('%-2s',['']);
DebugDL.Parm6:=Format('%-2s',['02']);
DebugDL.Parm7:=Format('%-5s',['96528']);

FSyn_Buf[0] := #2;
FSyn_Buf[1] := #0;
FSyn_Buf[2] := #0;

iPkglen:= sizeof(DebugDL); //数据包长度

iTotalPkg:= htons(word(iPkglen)); <font color=red>(*为什么运行到这句要发生错误*)</font>

//建立连接
ClientSocket:= TClientSocket.Create(nil);
TheStream:= TWinSocketStream.Create(ClientSocket.Socket,6000);
ClientSocket.ClientType:= ctBlocking;
ClientSocket.Address:= '172.16.2.1';
ClientSocket.Port :=3000;
ClientSocket.Open;


TheStream.Write(FSyn_Buf,4); //发包头
TheStream.Write(iTotalPkg,2); //发长度
// TheStream.Write(htons(iTotalPkg),2); //发内容

FillChar(Buffer1, 5, 0);
if TheStream.WaitForData(6000) then begin
TheStream.Read(Buffer1,4);
for i:=0 to 5-1 do //前4位是包的长度
strRec:=strRec+Buffer1;
showmessage(strRec);
end;


end;
 
计算机处理器有两种排序方式:big-endian和little-endian。
intel86处理器用little-endian:字节的排序是从最无意义的字节到最有意义的字节。称为“主机字节顺序”。
在网络上指定IP地址和端口号,必须用big-endian来表示:从最有意义的字节到最无意义的字节。一般称之为“网络字节顺序”。
主机字节顺序与网络字节顺序的转换函数:
u_long htonl(u_long hostlogn);

int WSAHtonl(
SOCKET s,
u_long hostlogn,
u_long FAR * lpnetlong
);

u_short htons(u_short hostshort);

int WSAHtons(
SOCKET s,
u_short hostshort,
u_short FAR * lpnetshort
);
htonl和WSAHtonl的hostlong参数是按主机字节顺序排序的一个4字节数。
htonl函数返回的数网络字节顺序,WSAHtonl函数通过lpnetlogn参数返回网络字节顺序排序数。用于IP地址转换。
htons和WSAHtons的hostshort参数是按主机字节顺序排序的一个2字节数。用于端口转换。
htons函数把这个hostshort参数当作按网络字节排序的一个2字节数返回,而WSAHtons函数则通过lpnetshort参数返回。

下面4个函数是前4个函数的逆向函数,它们把网络字节顺序转换成主机字节顺序:
u_long ntohl(u_long netlong);

int WSANtohl(
SOCKET s,
u_long netlog,
u_long FAR * lphostlong
);

u_short ntohs(u_short netshort);

int WSANtohs(
SOCKET s,
u_short netshort,
u_short FAR * lphostshort
);

例:
var
InternetAddr: TSockAddrIn;
const
nProtId = 5150; //端口号。主机字节顺序排序格式
cp = '136.149.3.29'; //IP地址。点分internet地址格式
begin
{使用IP地址族}
InternetAddr.sin_family := AF_INET;
{将cp转换为4字节整数,并把它分配给sin_addr}
InternetAddr.sin_addr.S_addr := inet_addr(cp);
{将字段转换为网络字节顺序,并分配给sin_port}
InternetAddr.sin_port := htons(nProtId);
end;
 
应当没有错的,最多出来一个warning(也许你的哪个编译开关不对所以无法运行?)。
因为Integer->Word强制类型转换可能造成数据失真。用iTotalPkg:= htons(word(Cardinal(iPkglen)))试试。

说句题外话:
iPkglen:= sizeof(DebugDL); //数据包长度
这句没有意义,因为iPkglen永远等于28(不管你param1~param7中有没有数据也不管你那里面的数据是什么)
 
TO:Another_eYes
我试过加Cardinal也没用,运行到Htons这句时屏幕就会弹出一个错误框好象
是什么内存地址出错什么的,是系统的。还有其他办法吗?
 
问题解决了,原因是我 use 了idwinsocket 应该use winsocket就对了
 
多人接受答案了。
 
后退
顶部