网络编程的地址
进行网络编程的时候我们需要知道一个结构体来标记网络地址
其包括协议族,ip, 端口等等, 可以理解为打电话时的电话号码
sockdddr
sockaddr在头文件#include<sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了,如下:
struct sockaddr {
sa_family_t sin_family;//地址族
char sa_data[14]; // not easy to use
//14字节,包含套接字中的目标地址和端口信息
};
一般常用的是
sockaddr_in 来代替sockaddr,
其头文件#include<netinet/in.h>
或#include <arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下:
struct sockaddr_in {
sa_family_t sin_family;//地址族
uint16_t sin_port; // 端口
// 地址为啥定义成这样,这是历史原因
struct in_addr sin_addr; // 地址
char sin_zero[8] // 不使用
}
struct in_addr {
in_addr_t s_addr;
//in_addr_t 一般为 32位的unsigned int,其字节顺序为网络顺序(network byte ordered),即该无符号整数采用大端字节序 。
}
大小端转换以及点分十进制和二进制 ip转换
- 数据在传输的时候有大端和小端的问题
主机可能和网络传输的大小端不一样, 所有我们会面临大端小端转换的问题 - 我们使用的 ip 地址一般是点分十进制192.168.0.1,但是在网络传输的时候,我们一般采用二进制ip(网络序的int)
字节序转换函数
1. uint32_t htonl(uint32_t hostlong); host to network long
2. uint16_t htons(uint16_t hostshort);
3. uint32_t ntohl(uint32_t netlong);
4. uint16_t ntohs(uint16_t netshort);
说明:在上述的函数中,h代表host;n代表network s代表short;l代表long
地址转换函数
早期的函数:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
// 将点分十进制转换成网络序二进制数值
// 返回值 0 为主机地址无效, 非 0 有效
// 和下面的函数inet_addr有些类似
in_addr_t inet_addr(const char *cp);
// 点分十进制转成网络字节序二进制
// 无效则返回-1,
// 该函数不能处理 255.255.255.255, 处理该地址也会返回-1
char *inet_ntoa(struct in_addr in);
// 网络二进制转为点分十进制ip 地址
// 该函数返回指向点分开的字符串地址(如192.168.1.10)的指针,该字符串的空间为静态分配的,这意味着在第二次调用该函数时,上一次调用将会被重写(复盖),所以如果需要保存该串最后复制出来自己管理!
- 只能处理IPv4的ip地址
- 注意参数是struct in_addr
现在:
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst); pointer to numberic
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
- p pointer
- n numbric
- 支持IPv4和IPv6
- 可重入函数
- 其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr。
- 因此函数接口是void *addrptr。
- 返回值 1 成功, 0, 表达式无效, -1 为出错