网络通信
网络通信其实就是位于网络中不同主机上面的2个进程之间的通信。
层次:
其中网卡是一个串转并设备,它与cpu是并行传输,与网络是串行传输。
传输媒介:
1.无线:wifi、蓝牙、zigbee、4g/5g等
2.有线:双绞线、同轴电缆、光纤等
开放系统互连参考模型(简称OSI):
物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
TCP/IP协议分层:
TCP/IP是用的最多的网络协议实现,共分为4层:数据链路层、网络层、传输层、应用层。
网络地址转换协议NAT(network address translation):
应用层发送数据时,系统会将该数据拆分成一定大小的数据,然后在每个数据前后添加包头包尾,组成一个数据包发送出去。其中,包头中有该主机在局域网中的内网ip。
路由器在向外网发送数据前,先将内网ip替换成路由器的外网ip,然后发送。
这个替换的操作即为NAT,作用是缓解IPv4的IP地址不够用的问题,最终的解决方案还要靠IPv6。
NAT穿透:
即实现两个不同局域网中的两个主机直接通信。应用场景如迅雷下载,a电脑从迅雷服务器上下载文件,迅雷服务器检测到某局域网中的一台主机上有同样的资源,利用NAT穿透实现两台主机之间的上传和下载。
IP地址:
IPv4由32位二进制数构成,IPv6为64位。
网络通信中是采用网络字节序(二进制)传输,而在人机交互中使用点分十进制方式显示。
IPv4的32位地址中,分为“网络地址”和“主机地址”两部分。子网掩码用来表明网络地址和主机地址各占多少位。根据两地址占位的多少区别,将IPv4分为5类,最常用的有3类:
A类——范围从0-127,前一段号码为网络号码,后三段为本地计算机号码。如10.0.0.1,其中0和127是保留地址。0表示所有ip地址,127.0.0.0地址用来做回环测试loopback。
B类——范围从128-191,前两段号码为网络号码,后两段为本地计算机号码。如172.168.1.1
C类——范围从192-223,前三段号码为网络号码,后一段为本地计算机号码。如192.168.1.1
服务器架构类型
CS架构(客户端服务器架构)C-client S-server
BS架构(浏览器服务器架构)B-broswer S-server
像QQ、网盘这一类就属于CS架构的app,一家服务器对应一家app。由于全世界存在无数的服务器,不能为每个服务器都提供一个app。这种情况下就用到了BS架构,即一个浏览器可以和无数服务器进行通信。
TCP协议
TCP协议工作在传输层,对上服务socket接口,对下调用IP层。
TCP协议提供字节流服务,即将要发送的信息进行分割,然后每个部分附上收发方地址端口、被分割的各部分编号等信息,打包后发送。
TCP协议面向连接,即需要建立连接后才能开始通信。(3次握手,4次挥手)
TCP协议提供可靠传输,不怕丢包、乱序等问题。
TCP三次握手:
参考:https://baijiahao.baidu.com/s?id=1654225744653405133&wfr=spider&for=pc
图中seq指报文序号。
握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:
1.客户端向服务器发送SYN报文,请求建立连接;
2.服务器回应ACK报文,同意连接;
3.客户端回应ACK报文,确认连接,此时两端均进入ESTABLISHED状态(连接成功)。可以进行数据传输。
TCP四次挥手:
客户端和服务器均可主动发起挥手操作,下面是客户端主动发起挥手操作的过程:
1.客户端发送FIN标记的报文,请求释放连接,随后进入半关闭阶段。客户端停止发送数据,但是仍可以接收服务器端的数据。
2.服务器回应一个ACK标记的报文,表示接受到释放请求。服务器回应ACK之后开始为释放连接做准备。
3.服务器发出FIN/ACK标记的报文,表示准备好释放连接。此时服务器停止向客户端方向发送数据,但是可以接收到数据。
4.客户端回应一个ACK标记的报文,表示收到释放的信号。服务器收到ACK后,断开连接。客户端发完ACK后等待2MSL后断开连接。
补充:MSL是Max segment lifetime,即tcp报文的最大生命周期,2MSL是FIN和ACK报文保持有效的最大时长。如果客户端发完ACK后,服务器端1MSL内没收到,则会再次发出FIN。这就是为什么客户端要等待2MSL后断开的原因。
(UDP协议略。)
Socket接口
socket接口为系统提供给应用调用的接口。
socket函数
int socket(int domain, int type, int protocol);
domain用来指定接口通信的域,常用的AF_INET即代表IPv4, AF_INET6即为IPv6。
type用来指定通信类型,常用的SOCK_STREAM代表tcp,SOCK_DGRAM代表udp。
protocol用来指定特定的协议,一般设为0使用默认的协议。
返回值为网络文件描述符的值,如果错误返回-1,同时设置errno的值。
bind函数
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
该函数socket接口绑定到一个IP地址和端口。
sockfd为被绑定的接口。
addr为要绑定的地址,该地址兼容IPv4和IPv6 。
addrlen为地址的大小。
listen函数
设置socket接口为被动监听模式。非阻塞函数。
int listen(int sockfd, int backlog);
sockfd为接口。
backlog用于定义服务器监听队列的最大长度。
accept函数
等待客户端的连接。阻塞函数。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
addr用来获取请求连接的IP地址。
connect函数
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd为socket的网络文件描述符。
addr为被连接的IP地址,该地址兼容IPv4和IPv6。
addrlen为IP地址的长度。
socket接口发送函数
一般情况下我们使用write函数即可,当我们用到特殊协议时需要用send。
ssize_t write(int fildes, const void *buf, size_t nbyte);
fildes为socket的网络文件描述符。
ssize_t send(int socket, const void *buffer, size_t length, int flags);
socket为socket的网络文件描述符。
flags为数据传输类型。0表示默认类型,MSG_EOR表示在数据结尾加一个标记(如果协议支持的话)。
socket接口接收函数
一般情况下我们使用read函数即可,当我们用到特殊协议时需要用recv。
ssize_t read(int fildes, void *buf, size_t nbyte);
ssize_t recv(int socket, void *buffer, size_t length, int flags);
socket网络地址的转换函数
1.ipv4地址转换
inet_aton和inet_addr 点分十进制转换为网络字节序
inet_ntoa 网络字节序转换为点分十进制
2.ipv4或ipv6地址转换
inet_ntop 网络字节序转换为点分十进制
inet_pton 点分十进制转换为网络字节序
补充 :上面connet和bind函数中所谓可以兼容IPv4和IPv6的结构体struct sockaddr,在使用IPv4地址时传入的为struct sockaddr_in结构体,IPv6对应struct sockaddr_in6 。这些类型的定义可以在/usr/include/netinet/in.h文件中找到。
TCP通信创建步骤
tcp服务器创建步骤:
1.创建服务器socket,socket()
2.绑定socket到ip地址和端口,bind()
3.设置socket为被动监听模式,listen()
4.等待客户端的连接,accept()
5.创建子进程,接收发送
tcp客户端创建步骤:
1.创建服务器socket,socket()
2.请求连接到服务器,connect()
3.发送接收
UDP通信创建步骤
udp服务器创建步骤:
1.创建服务器socket,socket()
2.绑定socket到ip地址和端口,bind()
3.接收发送
udp客户端创建步骤:
1.创建服务器socket,socket()
2.发送接收