linux编程网络字节htons以及地址结构sockaddr理解

最近学习linux编程相关的东西,对sockaddr以及htons等函数有些理解,搜集了一些资料,整理如下:


创建ipv4的地址结构变量并初始化的常见代码如下:

int port = 12345;//端口号
const char* ip = "192.168.1.120";//IP
struct sockaddr_in address;
bzero(&address,sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET,ip,&address.sin_addr);
address.sin_port = htons(ip);

int sock = socket(AF_INET,SOCK_STREAM,0);

int ret = bind(sock,(struct sockaddr*)&address,sizeof(address));//地址绑定 或 sock命名

该代码几乎成为所有网络代码的基础,里面主要涉及字节序和sockaddr结构体相关的两个知识点。

其中字节序:

大端序:又称网络序

小端序:PC上主流的字节序


不同PC(或者说CPU)所采用的字节序是不一样的,这样两台PC通信的过程中,会出现字节序不符而导致通信失败,因此API提供相关函数去处理字节序相关的问题,最简单的方法以及本代码所表现出来的,就是统一将机器字节序转化为网络序即大端序,这样通信就可以独立于机器限制了。


初始化struct sockaddr结构体时,用到了两个函数inet_pton,htons,这两个函数均是处理输入并转化为网络序,inet_pton将ip字符串转化为网络序,是inet_aton的改进(string to network的简写),inet_pton能同时处理IPV4,IPV6两种。htons函数(host to network short)将字符串转化为short类型的网络字节序。两个函数的作用这里已经很清楚了,用于字节序的转化。

关于sockaddr结构体,在大部分的API函数中需要的是sockaddr结构体,而我们定义的地址结构体一般为sockaddr_in或者sockaddr_in6来代表IPV4/IPV6地址。其定义如下:

#include 

// All pointers to socket address structures are often cast to pointers
// to this type before use in various functions and system calls:

struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};


// IPv4 AF_INET sockets:

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

struct in_addr {
    unsigned long s_addr;          // load with inet_pton()
};


// IPv6 AF_INET6 sockets:

struct sockaddr_in6 {
    u_int16_t       sin6_family;   // address family, AF_INET6
    u_int16_t       sin6_port;     // port number, Network Byte Order
    u_int32_t       sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr;     // IPv6 address
    u_int32_t       sin6_scope_id; // Scope ID
};

struct in6_addr {
    unsigned char   s6_addr[16];   // load with inet_pton()
};


// General socket address holding structure, big enough to hold either
// struct sockaddr_in or struct sockaddr_in6 data:

struct sockaddr_storage {
    sa_family_t  ss_family;     // address family

    // all this is padding, implementation specific, ignore it:
    char      __ss_pad1[_SS_PAD1SIZE];
    int64_t   __ss_align;
    char      __ss_pad2[_SS_PAD2SIZE];
};

sockaddr_in和sockaddr其地址开始的部分是相同的,即可以相互转化。为何要转化,因为IP4,IP6两种地址并不相同,为了使API能共通用化,所以使用sockaddr能同时接受两种地址的输入。

关于sockaddr参考文章可见:https://beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html  (2016/3/2)


你可能感兴趣的:(LINUX编程)