持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
- 英文小册原文地址:beej.us/guide/bgnet…
- 作者:Beej
- 中文翻译地址:www.chanmufeng.com/posts/netwo…
现将目录贴下:
- 什么是socket
- IP地址、struct以及地址转换
- IP地址,IPv4和IPv6
- 子网
- 字节序
- socket相关的数据结构
- 再谈IP地址
- 从IPv4迁移到IPv6
- System call 或 Bust
- getaddrinfo()—准备开始!
- socket()—拿到文件描述符!
- bind()—我在监听哪个端口?
- connect()—嘿,你好啊!
- listen()—会有人联系我吗?
- accept()—感谢呼叫3490端口
- send() and recv()—跟我唠唠吧,宝儿!
- sendto() and recvfrom()—用DGRAM风格跟我说话
- close() and shutdown()—滚犊子!
- getpeername()—你哪位?
- gethostname()—我是谁?
- Client-Server基础
- 一个简单的流服务器
- 一个简单的流客户端
- Datagram Sockets
- 技术进阶
- Blocking—何谓阻塞?
- poll()—同步的I/O多路复用
- select()—老古董的同步I/O多路复用
- 数据只传了一部分怎么办?
- Serialization-如何封装数据?
- 数据封装
- 广播数据包-大声说「Hello,World」
不得不说,我们真的很幸运,如今已经有了很多函数可以让我们操作IP地址,而不需要我们自己用long
类型数据以及<<
运算符来处理它们。
假如你声明了一个数据结构struct sockaddr_in ina
,你还有一个“10.12.110.57
”或“2001:db8:63b3:1::3490
”这样的IP地址,该怎么把IP地址存入ina
呢。
IP转二进制
你可以使用inet_pton()
将点分十进制形式的IPv4地址保存在ina
中,但如果要保存IPv6地址的话,我们就需要struct sockaddr_in6 ina6
了。
“
pton
”的全称是“presentation to network”,也可以是“printable to network”,选一个能帮助你记忆的就行。
具体的转换如下代码所示:
struct sockaddr_in sa; // IPv4
struct sockaddr_in6 sa6; // IPv6
inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); // IPv4
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6
小记:原本的老方法是使用名为
inet_addr()
或是inet_aton()
的函数;这些函数已经过时了,而且不适用于 IPv6
上面的程序写的比较简单,而且不够健壮,因为没有进行错误检查。inet_pton()
在发生错误时会返回-1
,而若地址无效则返回0
。所以在使用之前要检查返回值,并保证返回结果是大于 0 的。
现在我们可以将字符串格式的IP地址转换为二进制形式了。那么反过来需要怎么做?
二进制转IP
如果我们已经有了struct in_addr
,怎么将点分十进制的IP打印出来?(或者我们有struct in6_addr
,怎么打印字符串类型的IPv6地址呢?)
我们可以使用inet_ntop()
函数,看代码:
“
ntop
”的全称是“network to presentation”,也可以是“network to printable”,选一个能帮助你记忆的就行。
// IPv4:
char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
struct sockaddr_in sa; // 假设sa中保存了ip信息
inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);
printf("The IPv4 address is: %s\n", ip4);
// IPv6:
char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
struct sockaddr_in6 sa6; // 假设sa6种保存了ip信息
inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);
printf("The address is: %s\n", ip6);
当我们调用inet_ntop()
,你需要传递IP地址类型(IPv4 或者 IPv6),一个指向保存字符串结果的指针以及该字符串的最大长度。有两个宏(可以理解为常量)可以很方便地帮助我们表示要存储的IPv4或者IPv6地址字符串的最大长度,分别是INET_ADDRSTRLEN
和 INET6_ADDRSTRLEN
。
小记:原本的老方法是使用名为
inet_ntoa()
的函数,这个函数已经过时了,而且不适用于 IPv6
最后,本文讲到的函数只能用于数值型的IP地址上,它们不会用DNS做域名解析,所以你传入“www.chanmufeng.com”这样的域名是没有用的。
关于域名查询,我们将会使用getaddrinfo()
函数,之前的文章提过一嘴,后文将会详细讲述,敬请期待。