Jimmy Chen

A Programmer

(整理)sockaddr_in、in_addr、sockaddr区别和Socket编程函数集

sockaddr_in, sockaddr, in_addr区别

网络字节序和主机字节序

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

网络字节序,UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待,这就要求发送端发送的第一个字节是高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处)。由此可见,多字节数值在发送之前,在内存中因该是以大端法存放的,所以说,网络字节序是大端字节序。

要判断自己的电脑是小端字节序和大端字节序,有很多方法,你可以自己构造一个union或者struct结构体,也可以直接用一个int值就好,只要能判断程序的低字节是存放在主机高字节处还是低字节处就行。下面是一个判断的简单方法:

  首先还是需要看看这几个结构体的内容,了解清楚这几个结构体是什么,对我们后续了解Socket编程函数集的时候都是有帮助的,起码能知道参数/返回值指的是结构体、二进制IP地址还是字符串什么的。

sockaddr_in和sockaddr

因为sockaddr_in和sockaddr都是16字节的结构体,是可以互相转换的,它们的内容如下:

上面是通用的socket地址,具体到Internet socket,用下面的结构,二者可以进行类型转换

sockaddr_in结构体中使用到的struct in_addr就是4字节、32位的IP地址。它的定义有两个,不过编程的时候用的比较多in_addr_t

另一个定义为:

所以,到这里其实对用到的结构体和一些定义名就比较清楚了,sockaddr和sockaddr_in这两个结构体是能够互用的,在要使用sockaddr的地方(比如bind、connect之类的函数)都可以将sockaddr_in结构体进行强制类型转换来使用。其次就是in_addr是一个struct结构体,而in_addr_t一般是一个unsigned int 32位的值,其字节顺序为网络顺序(network byte ordered)。

常用Socket函数集

16位 or 32位整数主机/网络字节序转换

上面这四个函数只是简单的将2字节 or 4字节的数在主机字节序和网络字节序之间转换,暂时用的比较多的应该是htons了,基本都是用这个函数来讲server或者client需要使用的端口号,从主机字节序转换成网络字节序的。

不安全的(不可重入性)inet_xxx()函数族

由于计算机理解的IP都是以二进制形式保存的,那么在网络程序设计中经常会需要字符串IP和二进制IP的转换,linux系统有一组要用于网络地址转换的函数,如下:

以上部分函数存在缺陷,例如:

inet_ntoa函数返回值是一个指向字符串的指针,此内存会在每次调用inet_nota函数的时候被覆盖掉,如果不及时拿走数据就会出现不可预料的错误,因此函数是不安全的,存在某种隐患;

inet_addr,inet_network函数的-1返回值是用来表示转换出错的,但是在使用255.255.255.255作为参数进行转换的时候,刚好溢出导致返回值为-1,因此是存在缺陷的,埋下了隐患。

下面用一段代码介绍使用方法和隐患的部分:

<

pre>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char argv[])
{
struct in_addr ip,local,network;
char addr1[]=”192.168.1.1″; /
网络地址字符串 /
char addr2[]=”255.255.255.255″;
char addr3[]=”192.16.1″;
char *str=NULL,
str2=NULL;

}

运行结果如下图:

《(整理)sockaddr_in、in_addr、sockaddr区别和Socket编程函数集》

安全的地址转换函数inet_pton(),inet_ntop()

函数inet_pton(),inet_ntop()都是可以重入的,同时支持多种地址类型,包含IPV4和IPV6。

函数介绍如下:

《(整理)sockaddr_in、in_addr、sockaddr区别和Socket编程函数集》

《(整理)sockaddr_in、in_addr、sockaddr区别和Socket编程函数集》

下面用一段代码介绍使用方法:

<

pre>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

#define ADDRLEN 16
int main(int argc, char argv[])
{
struct in_addr ip;
char IPSTR[]=”192.168.1.1″; /
网络地址字符串 /
char addr[ADDRLEN]; /
保存转换后的字符串IP地址,16个字节大小 /
const char
str=NULL;
int err = 0; /* 返回值 */

}

运行结果:

参考博客(感谢两位博主):

  • http://blog.csdn.net/wh_19910525/article/details/54603487
  • http://blog.csdn.net/hnlyyk/article/details/47976161

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注