《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(1)
2015-01-16 17:19
1096 查看
先来学习一下《Linux高性能服务器编程》第五章 Linux网络编程基础API。
Linux网络API分为三个方面:socket地址API,socket基础API,网络信息API。
socket地址API主要是跟socket地址转换相关的一些API,socket地址包含IP地址和端口,唯一标示了TCP通信的一端;
socket基础API主要有创建socket,命名socket,监听socket,接受连接,发起连接,读写数据,获取地址信息,检测带外标记以及读取和设置socket选项。一般定义在sys/socket.h头文件中;
网络信息API实现主机名和IP地址之间、服务名称和端口号之间的转换,定义在netdb.h头文件中。
一、socket地址API
1、主机字节序和网络字节序
大端:整数的高位字节存储在内存的低地址处,低位字节存储在高地址处;
小端:整数的高位字节存储在内存的高地址处,低位字节存储在低地址处;
PC大多采用小端字节序,所以小端字节序也称为主机字节序。
为在不同字节序的主机之间传送数据,发送端总是把数据转成大端,接收端也知道收到的数据总是大端字节序,然后根据自己的字节序决定是否需要转换。大端字节序也称为网络字节序。
注意:即使同一机器上的两个进程通信,也要考虑字节序。(比如一个由C语言编写,一个由Java编写,Java虚拟机采用大端)
Linux提供4个函数完成两种字节序的转换:
#include<netinet/in.h>
unsigned long int htonl(unsigned longint hostlong);
unsigned short int htons(unsignedshort int hostshort);
unsigned long int ntohl(unsigned longint netlong);
unsigned short int ntohs(unsignedshort int netshort);
2、通用socket地址
socket地址结构体sockaddr:
#include <bits/socket.h>
struct sockaddr
{
sa_family_tsa_family;
charsa_data[14];
}
其中,sa_family_t sa_family表示地址族,地址族类型通常与协议族类型对应,如下表:
PF_*和AF_*都定义在bits/socket.h头文件中,二者值相同,经常混用。
sa_data用于存放socket地址值,不同协议族的地址值含义和长度不同:
14字节sa_data无法容纳多数协议族的地址值,因此Linux定义了新的通用socket地址结构体:
#include<bits/socket.h>
structsockaddr_storage
{
sa_family_t sa_family;
unsigned long int __ss_align;
char __ss_padding[128-sizeof(__ss_align)];
}
该结构体提供了足够的空间存储地址,并且是内存对齐的。
3、专用socket地址
通用地址很不好用,设置与获取IP地址和端口号需要繁琐的位操作。Linux为各个协议族提供了专门的socket地址结构体。
UNIX本地协议族使用如下socket地址结构体:
#include<sys/un.h>
struct sockaddr_un
{
sa_family_t sin_family;/*地址族AF_UNIX*/
char sun_path[108];/*文件路径名*/
};
TCP/IP协议族有sockaddr_in和sockaddr_in6两个结构体,分别对应IPv4和IPv6:
struct sockaddr_in
{
sa_family_t sin_family;/*地址族:AF_INET*/
u_int16_t sin_port;/*端口号,网络字节序表示*/
struct in_addr sin_addr;/*IPv4地址结构体*/
};
struct in_addr
{
u_int32_t s_addr;/*IPv4地址,网络字节序表示*/
};
struct sockaddr_in6
{
sa_family_t sin6_family;/*地址族:AF_INET6*/
u_int16_t sin6_port;/*端口号,网络字节序*/
u_int32_t sin6_flowinfo;/*流信息,应设置为0*/
struct in6_addr sin6_addr;/*IPv6地址结构体*/
u_int32_t sin6_scope_id;/*scope ID,尚处于实验阶段*/
};
struct in6_addr
{
unsigned char sa_addr[16];/*IPv6地址,网络字节序*/
};
所有专业socket地址类型变量使用时需要强制转换为sockaddr通用地址类型,所有socket编程接口的地址参数类型都是sockaddr。
4、IP地址转换函数
点分十进制字符串表示IPv4地址,十六进制表示IPv6地址,可读性更好,但编程时需要把它们转为二进制整数才能使用。下面3个函数用于点分十进制和网络字节序整数表示的IPv4地址间的转换:
#include <arpa/inet.h>
in_addr_t inet_addr(const char* strptr);
int inet_aton(const char* cp, struct in_addr* inp);
char* inet_ntoa(struct in_addr in);
inet_addr函数将点分十进制字符串转化为网络字节序整数IPv4地址,失败返回INADDR_NONE。
inet_aton函数功能相同,但将转化结果保存在inp参数指向的地址中,成功返回1,失败返回0。
inet_ntoa函数将网络字节序整数转化为点分十进制字符串。注意该函数内部用一静态变量保存转化结果,函数返回值指向该静态内存,该函数不可重入。如果连续调用该函数两次,之后再获取两次的结果,则只保存了最后一次的结果。
下面两个函数与上面三个函数功能相同,可用于IPv4和IPv6:
#include <arpa/inet.h>
int inet_pton(int af, const char* src, void* dst);
const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt);
inet_pton函数将字符串表示的IP地址src(点分十进制表示的IPv4或十六进制表示的IPv6)转为网络字节序整数,结果保存在dst指向的内存中。参数af表示地址族,AF_INET或AF_INET6,函数成功返回1,失败返回0并设置errno。
inet_ntop操作相反,最后一个参数cnt指定目标存储单元的大小,有两个宏:
#include<netinet/in.h>
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
成功返回目标存储单元地址,失败返回NULL,并设置errno。
以上为socket地址API相关的内容,主要是对socket地址的定义和转换。之后看socket基础API,主要是socket的基本操作。
Linux网络API分为三个方面:socket地址API,socket基础API,网络信息API。
socket地址API主要是跟socket地址转换相关的一些API,socket地址包含IP地址和端口,唯一标示了TCP通信的一端;
socket基础API主要有创建socket,命名socket,监听socket,接受连接,发起连接,读写数据,获取地址信息,检测带外标记以及读取和设置socket选项。一般定义在sys/socket.h头文件中;
网络信息API实现主机名和IP地址之间、服务名称和端口号之间的转换,定义在netdb.h头文件中。
一、socket地址API
1、主机字节序和网络字节序
大端:整数的高位字节存储在内存的低地址处,低位字节存储在高地址处;
小端:整数的高位字节存储在内存的高地址处,低位字节存储在低地址处;
PC大多采用小端字节序,所以小端字节序也称为主机字节序。
为在不同字节序的主机之间传送数据,发送端总是把数据转成大端,接收端也知道收到的数据总是大端字节序,然后根据自己的字节序决定是否需要转换。大端字节序也称为网络字节序。
注意:即使同一机器上的两个进程通信,也要考虑字节序。(比如一个由C语言编写,一个由Java编写,Java虚拟机采用大端)
Linux提供4个函数完成两种字节序的转换:
#include<netinet/in.h>
unsigned long int htonl(unsigned longint hostlong);
unsigned short int htons(unsignedshort int hostshort);
unsigned long int ntohl(unsigned longint netlong);
unsigned short int ntohs(unsignedshort int netshort);
2、通用socket地址
socket地址结构体sockaddr:
#include <bits/socket.h>
struct sockaddr
{
sa_family_tsa_family;
charsa_data[14];
}
其中,sa_family_t sa_family表示地址族,地址族类型通常与协议族类型对应,如下表:
协议族 | 地址族 | 描述 |
PF_UNIX | AF_UNIX | UNIX本地协议族 |
PF_INET | AF_INET | TCP/IPv4协议族 |
PF_INET6 | AF_INET6 | TCP/IPv6协议族 |
sa_data用于存放socket地址值,不同协议族的地址值含义和长度不同:
协议族 | 地址值含义和长度 |
PF_UNIX | 文件路径名,最大长度108字节 |
PF_INET | 16bit端口号和32bit IPv4地址,6字节 |
PF_INET6 | 16bit端口号和32bit流标识,128bit IPv6地址,32bit范围ID,共26字节 |
14字节sa_data无法容纳多数协议族的地址值,因此Linux定义了新的通用socket地址结构体:
#include<bits/socket.h>
structsockaddr_storage
{
sa_family_t sa_family;
unsigned long int __ss_align;
char __ss_padding[128-sizeof(__ss_align)];
}
该结构体提供了足够的空间存储地址,并且是内存对齐的。
3、专用socket地址
通用地址很不好用,设置与获取IP地址和端口号需要繁琐的位操作。Linux为各个协议族提供了专门的socket地址结构体。
UNIX本地协议族使用如下socket地址结构体:
#include<sys/un.h>
struct sockaddr_un
{
sa_family_t sin_family;/*地址族AF_UNIX*/
char sun_path[108];/*文件路径名*/
};
TCP/IP协议族有sockaddr_in和sockaddr_in6两个结构体,分别对应IPv4和IPv6:
struct sockaddr_in
{
sa_family_t sin_family;/*地址族:AF_INET*/
u_int16_t sin_port;/*端口号,网络字节序表示*/
struct in_addr sin_addr;/*IPv4地址结构体*/
};
struct in_addr
{
u_int32_t s_addr;/*IPv4地址,网络字节序表示*/
};
struct sockaddr_in6
{
sa_family_t sin6_family;/*地址族:AF_INET6*/
u_int16_t sin6_port;/*端口号,网络字节序*/
u_int32_t sin6_flowinfo;/*流信息,应设置为0*/
struct in6_addr sin6_addr;/*IPv6地址结构体*/
u_int32_t sin6_scope_id;/*scope ID,尚处于实验阶段*/
};
struct in6_addr
{
unsigned char sa_addr[16];/*IPv6地址,网络字节序*/
};
所有专业socket地址类型变量使用时需要强制转换为sockaddr通用地址类型,所有socket编程接口的地址参数类型都是sockaddr。
4、IP地址转换函数
点分十进制字符串表示IPv4地址,十六进制表示IPv6地址,可读性更好,但编程时需要把它们转为二进制整数才能使用。下面3个函数用于点分十进制和网络字节序整数表示的IPv4地址间的转换:
#include <arpa/inet.h>
in_addr_t inet_addr(const char* strptr);
int inet_aton(const char* cp, struct in_addr* inp);
char* inet_ntoa(struct in_addr in);
inet_addr函数将点分十进制字符串转化为网络字节序整数IPv4地址,失败返回INADDR_NONE。
inet_aton函数功能相同,但将转化结果保存在inp参数指向的地址中,成功返回1,失败返回0。
inet_ntoa函数将网络字节序整数转化为点分十进制字符串。注意该函数内部用一静态变量保存转化结果,函数返回值指向该静态内存,该函数不可重入。如果连续调用该函数两次,之后再获取两次的结果,则只保存了最后一次的结果。
下面两个函数与上面三个函数功能相同,可用于IPv4和IPv6:
#include <arpa/inet.h>
int inet_pton(int af, const char* src, void* dst);
const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt);
inet_pton函数将字符串表示的IP地址src(点分十进制表示的IPv4或十六进制表示的IPv6)转为网络字节序整数,结果保存在dst指向的内存中。参数af表示地址族,AF_INET或AF_INET6,函数成功返回1,失败返回0并设置errno。
inet_ntop操作相反,最后一个参数cnt指定目标存储单元的大小,有两个宏:
#include<netinet/in.h>
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
成功返回目标存储单元地址,失败返回NULL,并设置errno。
以上为socket地址API相关的内容,主要是对socket地址的定义和转换。之后看socket基础API,主要是socket的基本操作。
相关文章推荐
- 《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(4)
- 《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(3)
- 《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(5)
- 《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(2)
- 5 Linux网络编程基础API
- Linux下的网络编程API基础
- Linux网络编程基础API
- Linux 高性能服务器编程——Linux网络编程基础API
- Linux高性能服务器编程——Linux网络基础API及应用
- 第二篇 深入解析高性能服务器编程 第5章 Linux 网络编程基础API
- socket 基础(Linux网络编程基础API)
- Linux 高性能服务器编程——Linux网络编程基础API
- Linux高性能server编程——Linux网络基础API及应用
- linux网络编程基础API(二)
- Linux网络编程基础API(多线程实现)
- Linux 高性能服务器编程——Linux网络编程基础API
- 服务器编程入门(4)Linux网络编程基础API
- 主机地址linux网络编程之TCP/IP基础(二):利用ARP和ICMP协议解释ping命令
- Linux 下C 网络编程 setsockopt getsockopt 基础练习
- 柳大的Linux讲义·基础篇(4)网络编程基础