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

来源:http://www.delphibbs.com/delphibbs/dispq.asp?lid=2190549

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[i];
   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;


来自: Another_eYes, 时间: 2003-09-22 7:56:00, ID: 2191192 
应当没有错的,最多出来一个warning(也许你的哪个编译开关不对所以无法运行?)。
因为Integer->Word强制类型转换可能造成数据失真。用iTotalPkg:= htons(word(Cardinal(iPkglen)))试试。

说句题外话:
iPkglen:= sizeof(DebugDL);                  //数据包长度
这句没有意义,因为iPkglen永远等于28(不管你param1~param7中有没有数据也不管你那里面的数据是什么)

来自: youjq, 时间: 2003-09-22 14:39:00, ID: 2192327 
TO:Another_eYes
我试过加Cardinal也没用,运行到Htons这句时屏幕就会弹出一个错误框好象
是什么内存地址出错什么的,是系统的。还有其他办法吗?


来自: youjq, 时间: 2003-09-22 18:16:00, ID: 2193094 
问题解决了,原因是我 use  了idwinsocket 应该use winsocket就对了

原文地址:https://www.cnblogs.com/railgunman/p/1885959.html