认识IP地址
- IP协议有两个版本, IPv4和IPv6,一般没有特殊说明的,默认为IPv4;
- IP地址是在IP协议中, ⽤用来标识⺴⽹网络中不同主机的地址;
- 对于IPv4来说, IP地址是⼀一个4字节, 32位的整数;
- 通常使用 “点分十进制” 的字符串表示IP地址, 例如 192.168.0.1 ; 用点分割的每⼀一个数字表 示一个字节, 范围是 0 -255。
认识端口号
端口号(port)是传输层协议的内容:
- 端口号是一个2字节16位的整数;
- 端口号用来标识⼀个进程, 告诉操作系统, 当前的这个数据要交给哪⼀个进程来处理;
- IP地址 +端⼝号(套接字)能够标识⺴络上的某⼀台主机的某⼀个进程 ;
- ⼀个端⼝号只能被⼀个进程占⽤ 。
理解 “端⼝号” 和 “进程ID”:
- 端口号和进程ID都是标识进程的,pid是表示唯一进程的,端口号也是唯一表示一个进程;
- 进程id: 所有的进程都有id;
- 端口号:只有网络通信时,进程才会有端口号;
- ⼀个进程可以绑定多个端⼝号;但是⼀个端⼝号不能被多个进程绑定。
TCP协议和UDP协议的区别
TCP协议:传输控制协议
特点:
(1)传输层协议;
(2)有连接;
(3)可靠传输;
(4)面向字节流;
UDP协议:用户数据报协议
特点:
(1)传输层协议;
(2)无连接;
(3)不可靠传输(高效传输);
(4)面向数据报;
网络字节序
内存中的多字节数据相对于内存地址有⼤端和⼩端之分 ,磁盘⽂件中的多字节数据相对于⽂件中的偏移地址也有⼤端⼩端之分 ,网络数据流同样有⼤端⼩端之分 。那么如何定义网络数据流的地址呢 ?
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
- 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
- 网络数据流的地址这样规定:先发出的数据是低地址,后发出的数据是高地址;
- TCP/IP协议规定,网络数据流采用大端字节序,即低地址高字节;
- 不管这台主机是大端机还是小端机,都会按照TCP/IP规定的网络字节序来发送、接收数据;
- 如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送即可。
为使网络程序具有可移植性 ,使同样的C代码在⼤端和⼩端计算机上编译后都能正常运⾏ ,可以调⽤以下库函数做网络字节序和主机字节序的转换。
#include<arpa/inet.h>
unit32_t htonl(unit32_t hostlong);
unit16_t htons(unit16_t hostshort);
unit32_t ntohl(unit32_t netlong);
unit16_t ntohs(unit16_t netshort);
- htonl:h表示host(主机),n表示network(网络),l表示long(32为长整数),s表示short(16位短整数);
- htons:表示:将short(16位短整数)从主机字节序转为网络字节序。例如,将ip地址转换后准备发送;
- 主机大端:函数不做转换,将参数原封不动返回;主机小端:函数做大小端的相应转换,然后返回。
- 这些函数名很好记,h表⽰host,n表⽰network,l表⽰32位⻓整数,s表⽰16位短整数;
- 例如htonl表⽰将32位的⻓整数从主机字节序转换为网络字节序 ,例如将IP地址转换后准备发送;
- 如果主机是⼩端字节序 ,这些函数将参数做相应的⼤⼩端转换然后返回 ;
- 如果主机是⼤端字节序 ,这些函数不做转换,将参数原封不动地返回。
socket编程接口
socket常见API:
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
socket结构
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6;然而, 各种网络协议的地址格式并不相同。
IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类 型,16位端口号和32位IP地址;
IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6。这样,只要取得某种sockaddr结构体的 首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.;
socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的 好处是程序的通⽤用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体 指针做为参数。