Winsock编程入门--2.寻址协议(IPv4)
IPv4寻址
IPv4中,计算机的地址用32位的二进制表示,称为IP地址.当客户机使用TCP或UDP与服务器通讯时,必须指定其IP地址及通讯端口.服务器想要侦听客户机请求时,也要指定IP地址与端口.Winsock中使用SOCKADDR_IN结构来设置这些信息:
struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; };
sin_family必须为AF_INET,设定Winsock使用IP地址族.
sin_port定义TCP或UDP的通讯端口. 端口要认真选择,一些知名服务使占用了特定的端口,如FTP及HTTP
sin_addr记录了IPv4的4字节地址,它是无符号长整型,IP地址通常以"a.b.c.d"表示,每个字母表示一个数字与IP地址的每个字节对应(从左到右)
sin_zero只是用来占用字节空间使得SOCKADDR_IN结构与SOCKADDR结构一样.
函数 inet_addr可以将字符串"a.b.c.d"格式的IP地址转换为32位无符号长整型的IP地址.
unsigned long inet_addr(const char FAR *cp);
cp就是指向null结尾的字符串形式IP地址.返回以网络字符顺序表示的IP地址.
字节顺序
不同计算机的处理器以big-endian或little-endian形式来表示数字.而IP地址与端口需要多个字节来表示,它们在不同计算机上的表示顺序称为主机字节顺序.而IP地址与端口在网络中的表示不应该有差异,必须以big-endian形式表示,称为网络字节顺序.
下面的Winsock API可以将主机字节顺序转换为网络字节顺序:
u_long htonl(u_long hostlong);
int WSAHtonl(SOCKET s, u_long hostlong, u_long FAR * lpnetlong);
u_short htons(u_short hostshort);
int WSAHtons( SOCKET s, u_short hostshort, u_short FAR * lpnetshort);
而下而的API则将网络字节顺序转换为主机字节顺序:
u_long ntohl(u_long netlong);
int WSANtohl(SOCKET s,u_long netlong, u_long FAR * lphostlong);
u_short ntohs(u_short netshort);
int WSANtohs(SOCKET s, u_short netshort, u_short FAR * lphostshort);
下面代码说明了如何用SOCKADDR_IN结构来设置地址与端口:
SOCKADDR_IN InternetAddr;
INT nPortId = 5150;
InternetAddr.sin_family = AF_INET;
//将字符串表示的IP地址转换为4个字节表示的整数,并赋值给sin_addr
InternetAddr.sin_addr.s_addr = inet_addr("136.149.3.29");
//nPortId变量以主机字节的顺序存储.将nPortId转换为网络字节顺序,并赋值给sin_port
InternetAddr.sin_port = htons(nPortId);
IP地址不是那么容易记忆,可以使用更友好的主机名来代替IP地址,比如www.somewebsite.com,用FTP来表示文件传输协议端口号21.与之相关的函数有:getaddrinfo, getnameinfo, gethostbyaddr, gethostbyname, gethostname, getprotobyname, getprotobynumber, get-servbyname, 及getservbyport. 这些函数的异步版本有: WSAAsyncGetHostByAddr, WSAAsyncGetHostByName, WSAAsyncGetProtoByName, WSAAsyncGetProtoByNumber, WSAAsyncGetServBy- Name,及WSAAsyncGetServByPort.