sockaddr与sockaddr_in及其使用

       编了有不少的socket相关的例子了,同时在现在的项目中常用到socket编程,今天突然发现对与socket编程中的地址使用还不是很熟练,于是综合一下网上的资料,详细探讨下.首先要说明的是这里主要探讨struct sockaddr 与struct sockaddr_in两个结构体.在linux环境下,结构体struct sockaddr在/usr/include/linux/socket.h中定义,具体定义如下:

typedef unsigned short sa_family_t;
struct sockaddr
{
   sa_family_t  sa_family;       /* 地址族,一般都是“AF_xxx”的形式,通常用的是AF_INET,2个字节 */
char sa_data[14]; /* 14字节的协议地址,包含该socket的IP地址和端口等信息 */
};

这是通用socket地址(共16字节).具体到internet环境下使用的socket的地址为sockaddr_in,二者长度一样,都是16个字节.二者可以进行类型转换.一般情况下,需要把sockaddr_in结构强制转换成sockaddr再传入系统调用函数中.

struct   sockaddr_in
{
    short int        sin_family;  /* 地址族,形如AF_xxx,通常用的是AF_INET,2字节 */   
    unsigned short int  sin_port;     /* 端口号(使用网络字节顺序)2字节 */   
    struct in_addr    sin_addr;     /* 存储IP地址,4字节,就是32位的ip地址 */   
    unsigned char       sin_zero[8]; /* 总共8个字节,实际上没有什么用,只是为了和struct sockaddr保持一样的长度 */   
};

struct in_addr其实就是32位IP地址,下面是in_addr的结构:

struct in_addr 
{
    unsigned long s_addr;
};

还有另一种形式,如下:

struct in_addr
{
    union
    {
        struct{unsigned char s_b1,s_b2,s_b3,s_b4;} S_un_b;
        struct{unsigned short s_w1,s_w2;} S_un_w;
        unsigned long S_addr;//4字节,32位,按照网络字节顺序存储IP地址
    } S_un;
};

 

    关于网络字节顺序:其实数据的顺序是由cpu决定的,与操作系统无关, Intel x86结构下,short型数0x1234表示为34 12,int型数0x12345678表示为78 56 34 12(小端数据),IBM power PC结构下,short型数0x1234表示为12 34,int型数0x12345678表示为12 34 56 78,则为大端数据.在网络传输时需要做好转换,网络字节顺序为大端字节顺序.下面是一些用于转换的函数.

htons:unsigned short类型从主机序转换到网络序;

htonl:unsigned long 类型从主机序转换到网络序;

ntohs:unsigned short类型从网络序转换到主机序;

ntohl:unsigned long 类型从网络序转换到主机序;

inet_aton(const char *string, struct in_addr*addr):将一个字符串IP地址转换为一个32位的网络序列IP地址

inet_addr:是将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001),即转换成in_addr,inet_addr()返回的地址已经是网络字节格式,所以无需再调用函数htonl();

inet_ntoa(struct in_addr):返回点分十进制的字符串在静态内存中的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址.

inet_pton(int af, const char *src, void *dst):函数将点分十进制的地址src转换为in_addr的结构体,并复制在dst中.

const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt):转换网络二进制结构到点分十进制类型的地址

例子:

my_addr.sin_family = AF_INET;  /* 主机字节序 */
my_addr.sin_port   = htons(MYPORT);  /* short, 网络字节序 */
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//还有如此的格式
my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");

一般编程中并不直接针对sockaddr操作,而是使用sockaddr_in来进行操作.要做转换的时候用:(struct sockaddr*)mysock_addr,填值的时候使用sockaddr_in结构,而作为函数的参数传入的时候转换成sockaddr结构就行了.

posted @ 2012-04-13 17:33  一线天  阅读(2774)  评论(0编辑  收藏  举报