第3章:套接字的地址结构
- 每个套接字都需要使用到套接字地址结构,这些结构在两个方向上传递,内核到进程和进程到内核,从内核到进程传递的是值-结果参数。
- 地址转换函数是将地址的文本表达和他们存放在内存中二进制值之间进行转换的一组函数
3.1套接字地址结构
- IPV4套接字地址结构
struct in_addr{ #存放ip地址
in_addr_t s_addr; /*32-bit IPv4 address*/
}; /*network byte ordered*/
struct sockaddr_in{ #存放sock地址所有信息,包含ip
unit8_t sin_len; /*length of structure(16)*/
sa_family_t sin_family; /*AF_INET*/
in_port_t sin_port; /*16-bit TCP or UDP port number*/
/*network byte ordered*/
struct in_addr sin_addr; /*32-bit IPv4 address, network byte ordered*/
char sin_zero[8];
- posix只需要这个结构中的sin_family,sin_addr,sin_port这三个字段
- POSIX总是以往来账字节序来存储IP地址
3.2通用套接字地址结构
- 套接字地址结构通常使用引用的方式传递
- 通用套接字地址结构是为了解决不同协议族之间套接字地址结构不同的问题
struct sockaddr{
unit8_t sa_len; /*address family:AF_xxx value*/
sa_family_t sa_family; /*protocol-specific address*/
char sa_data[14] ;
- 套接字函数都被定义为以指向某个通用套接字地址结构的一个指针作为其参数之一,所以函数的任何调用都要进行强制类型转换,举例如下
struct sockaddr_in server ;
int bind(int, (struct sockaddr *) &server, sizeof(server));
ipv6套接字地址结构,后补
新的通用套接字地址结构
套接字地址结构的比较
3.3值-结果参数
传递套接字地址结构的时候,传递的套接字地址结构是一个引用还是值取决于传递的方向:是从内核到进程还是从进程到内核
- 从进程到内核传递的函数有三个
- bind
- connect
- sendto
- 这些函数的一个参数是指向sockaddr_in的指针,另一个参数是整数大小,指针和指针大小内核用于判断到底从进程复制多少数据到内核
- 从内核到进程
- accept
- resvform
- getsockname
- getpeername
- 这些函数的两个参数是指向套接字地址结构的指针和指向该结构大小的指针,其中结构的长度使用引用的原因是:当函数被调用的时候,引用可以告诉内核需要复制多少数据到内核,这样在写结构的时候不至于越界,而在函数返回的时候,这个指针告诉进程到底在结构中写入了多少数据。这种参数称为值-结果参数
3.4字节排序函数
考虑存储一个16位的整数,内存中存储有两种方式一种是将低序字节存储在字节起始位置,这叫小端字节序。一种是吧高序字节存在起始位置,这叫大端字节序。
- 不同的主机对于使用哪种字节序有自己的实现,我们把主机的字节序叫主机字节序。
- 下面的程序可以测试系统的字节序是大端法还是小端法
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
union{
short s;
char c[sizeof(short)];
}un;
un.s = 0x0102;
if(sizeof(short) == 2){
if(un.c[0] == 1 && un.c[1] == 2)
printf("big-endian\n");
else if(un.c[0] == 2 && un.c[1] == 1)
printf("little-endian\n");
else
printf("unkonwn\n");
}else
printf("sizeof(short) = %d\n", sizeof(short));
exit(0);
}
- 每个TCP segment都有一个32 big的ipv4地址和16 bit的端口,协议栈必须对字节顺序保持一致,网络字节序使用大端字节序
- 主机字节序和网络字节序之间的转换使用下面的函数
#include <netinet/in.h>
unit16_t htons(unit16_t host16bitvalue);
unit32_t htons(unit32_t host32bitvalue);/*返回网络字节序的值*/
unit16_t ntohs(unit16_t net16bitvalue);
unit32_t ntohs(unit32_t net32bitvalue); /*返回主机字节序的值*/
3.5 字节操纵函数
- 操纵多字节字段的函数有两组:它们既不对数据做解释,也不假设数据是以空字符结束的字符串。仅仅把数据当作连接的数据bit。
#include <string.h>
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, size_t bytes);
int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
#include <string.h>
void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, const void *src, size_t nbytes);
int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
3.6 地址转换函数inet_aton,inet_ntoa,inet_addr
- 我们需要把一个ip地址从ACSII字符串(常用的ipv4点分十进制的表达形式)和网络字节序之间进行转换,
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
//返回:若字符串有效则为1,否则为0
in_addr_t inet_addr(const char *strptr); #该函数已经弃用,尽量另外两个
//返回:若字符串有效则为32位二进制网络字节序的IPV4地址,否则为INADDR_None
char *inet_ntoa(struct in_addr inaddr);
//返回:指向一个点分十进制数串的指针
示例:
#include <netinet/in.h>
#include <string>
#include <arpa/inet.h>
#include <string>
#include <iostream>
int
main(){
string ipEnd0 = "10.10.10.10";
struct in_addr netaddr ;
inet_aton(ipEnd0.c_str(), &netaddr) ;
cout<< netaddr.s_addr << endl ;
}
3.7 inet_pton ,inet_ntop函数
- 这两个函数同样用于ASCII和ipv4地址之间的转换,但同时支持ipv4和ipv6,其中p和n分别表示numeric和presentation(表达)。
#include<arpa/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr);
返回:若成功则为1,若输入不是有效的表达格式则为0,若出错则为-1
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
返回:若成功则为指向结果的指针, 若出错则为NULL
- 这两个函数的family参数既可以是AF_INET,也可以是AF_INET6。如果以不被支持的地址族作为family的参数,这两个函数就都返回一个错误,并将errno置为EAFNOSUPPORT。
- 第一个函数尝试转换由strptr指针所指的字符串,并通过addrptr指针存放二进制结果。若成功则返回1,否则如果对所指定的family而言输入的字符串不是有效的表达式,那么值为0。
- inet_ntop进行相反的转换,从数值格式(addrptr)转换到表达格式(strptr)。len参数是目标存储单元的大小,以免该函数溢出其调用者的缓冲区。
示例:
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
int main()
{
struct in_addr addr;
if(inet_pton(AF_INET, "127.0.0.1", &addr.s_addr) == 1)
printf("NetIP: %x\n", addr.s_addr);
char str[20];
if(inet_ntop(AF_INET, &addr.s_addr, str, sizeof str))
printf("StrIP: %s\n", str);
return 0;
}
网友评论