IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 极客网络学习 -> 正文阅读

[系统运维]极客网络学习

网络编程模型:认识客户端-服务器网络模型的基本概念

国际标准组织在 IPv4 地址空间里面,专门划出了一些网段,这些网段不会用做公网上的 IP,而是仅仅保留作内部使用,我们把这些地址称作保留网段。
下表是三个保留网段,其可以容纳的计算机主机个数分别是 16777216 个、1048576 个和 65536 个。
在这里插入图片描述
TCP 通过诸如连接管理,拥塞控制,数据流与窗口管理,超时和重传等一系列精巧而详细的设计,提供了高质量的端到端的通信方式。
UDP 在很多场景也得到了极大的应用,比如多人联网游戏、视频会议,甚至聊天室。

socket 到底是什么?
在这里插入图片描述
因为在客户端发起连接请求之前,服务器端必须初始化好。右侧的图显示的是服务器端初始化的过程,首先初始化 socket,之后服务器端需要执行 bind 函数,将自己的服务能力绑定在一个众所周知的地址和端口上,紧接着,服务器端执行 listen 操作,将原先的 socket 转化为服务端的 socket,服务端最后阻塞在 accept 上等待客户端请求的到来。此时,服务器端已经准备就绪。客户端需要先初始化 socket,再执行 connect 向服务器端的地址和端口发起连接请求,这里的地址和端口必须是客户端预先知晓的。这个过程,就是著名的 TCP 三次握手(Three-way Handshake)。
一旦三次握手完成,客户端和服务器端建立连接,就进入了数据传输过程。具体来说,客户端进程向操作系统内核发起 write 字节流写操作,内核协议栈将字节流通过网络设备传输到服务器端,服务器端从内核得到信息,将字节流从内核读入到进程中,并开始业务逻辑的处理,完成之后,服务器端再将得到的结果以同样的方式写给客户端。可以看到,一旦连接建立,数据的传输就不再是单向的,而是双向的,这也是 TCP 的一个显著特性。当客户端完成和服务器端的交互后,比如执行一次 Telnet 操作,或者一次 HTTP 请求,需要和服务器端断开连接时,就会执行 close 函数,操作系统内核此时会通过原先的连接链路向服务器端发送一个 FIN 包,服务器收到之后执行被动关闭,这时候整个链路处于半关闭状态,此后,服务器端也会执行 close 函数,整个链路才会真正关闭。半关闭的状态下,发起 close 请求的一方在没有收到对方 FIN 包之前都认为连接是正常的;而在全关闭的状态下,双方都感知连接已经关闭。

TCP

如果是 TCP 套接字,那么调用 connect 函数将激发 TCP 的三次握手过程,而且仅在连接建立成功或出错时才返回。其中出错返回可能有以下几种情况:三次握手无法建立,客户端发出的 SYN 包没有任何响应,于是返回 TIMEOUT 错误。这种情况比较常见的原因是对应的服务端 IP 写错。客户端收到了 RST(复位)回答,这时候客户端会立即返回 CONNECTION REFUSED 错误。这种情况比较常见于客户端发送连接请求时的请求端口写错,因为 RST 是 TCP 在发生错误时发送的一种 TCP 分节。产生 RST 的三个条件是:目的地为某端口的 SYN 到达,然而该端口上没有正在监听的服务器(如前所述);TCP 想取消一个已有连接;TCP 接收到一个根本不存在的连接上的分节。客户发出的 SYN 包在网络上引起了"destination unreachable",即目的不可达的错误。这种情况比较常见的原因是客户端和服务器端路由不通。

在这里插入图片描述
下面是具体的过程:
1.客户端的协议栈向服务器端发送了 SYN 包,并告诉服务器端当前发送序列号 j,客户端进入 SYNC_SENT 状态;
2.服务器端的协议栈收到这个包之后,和客户端进行 ACK 应答,应答的值为 j+1,表示对 SYN 包 j 的确认,同时服务器也发送一个 SYN 包,告诉客户端当前我的发送序列号为 k,服务器端进入 SYNC_RCVD 状态;
3.客户端协议栈收到 ACK 之后,使得应用程序从 connect 调用返回,表示客户端到服务器端的单向连接建立成功,客户端的状态为 ESTABLISHED,同时客户端协议栈也会对服务器端的 SYN 包进行应答,应答数据为 k+1;
4.应答包到达服务器端后,服务器端协议栈使得 accept 阻塞调用返回,这个时候服务器端到客户端的单向连接也建立成功,服务器端也进入 ESTABLISHED 状态。

使用套接字进行读写

发送数据
发送数据时常用的有三个函数,分别是 write、send 和 sendmsg。

ssize_t write (int socketfd, const void *buffer, size_t size)
ssize_t send (int socketfd, const void *buffer, size_t size, int flags)
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)

第一个函数是常见的文件写函数,如果把 socketfd 换成文件描述符,就是普通的文件写入。如果想指定选项,发送带外数据,就需要使用第二个带 flag 的函数。所谓带外数据,是一种基于 TCP 协议的紧急数据,用于客户端 - 服务器在特定场景下的紧急处理。如果想指定多重缓冲区传输数据,就需要使用第三个函数,以结构体 msghdr 的方式发送数据。

对于套接字描述符而言,它代表了一个双向连接,在套接字描述符上调用 write 写入的字节数有可能比请求的数量少,因为
发送缓冲区
当 TCP 三次握手成功,TCP 连接成功建立后,操作系统内核会为每一个连接创建配套的基础设施,比如发送缓冲区。发送缓冲区的大小可以通过套接字选项来改变,当我们的应用程序调用 write 函数时,实际所做的事情是把数据从应用程序中拷贝到操作系统内核的发送缓冲区中,并不一定是把数据通过套接字写出去。
作系统内核的发送缓冲区不足以容纳应用程序数据时,操作系统内核并不会返回,也不会报错,而是应用程序被阻塞,也就是说应用程序在 write 函数调用处停留,不直接返回,大部分 UNIX 系统的做法是一直等到可以把应用程序数据完全放到操作系统内核的发送缓冲区中,再从系统调用中返回。当 TCP 连接建立之后,它就开始运作起来。你可以把发送缓冲区想象成一条包裹流水线,有个聪明且忙碌的工人不断地从流水线上取出包裹(数据),这个工人会按照 TCP/IP 的语义,将取出的包裹(数据)封装成 TCP 的 MSS 包,以及 IP 的 MTU 包,最后走数据链路层将数据发送出去。这样我们的发送缓冲区就又空了一部分,于是又可以继续从应用程序搬一部分数据到发送缓冲区里,这样一直进行下去,到某一个时刻,应用程序的数据可以完全放置到发送缓冲区里。在这个时候,write 阻塞调用返回。注意返回的时刻,应用程序数据并没有全部被发送出去,发送缓冲区里还有部分数据,这部分数据会在稍后由操作系统内核通过网络发送出去。

读取数据
read 函数

ssize_t read (int socketfd, void *buffer, size_t size)

read 函数要求操作系统内核从套接字描述字 socketfd读取最多多少个字节(size),并将结果存储到 buffer 中。返回值告诉我们实际读取的字节数目,也有一些特殊情况,如果返回值为 0,表示 EOF(end-of-file),这在网络中表示对端发送了 FIN 包,要处理断连的情况;如果返回值为 -1,表示出错。

可以无限增大缓冲区吗?
答:write函数发送数据只是将数据发送到内核缓冲区,而什么时候发送由内核觉定。内核缓冲区总是充满数据时会产生粘包问题,同时网络的传输大小MTU也会限制每次发送的大小,最后由于数据堵塞需要消耗大量内存资源,资源使用效率不高。

什么是TCP粘包?怎么解决这个问题

UDP 编程
在这里插入图片描述
服务器端创建 UDP 套接字之后,绑定到本地端口,调用 recvfrom 函数等待客户端的报文发送;客户端创建套接字之后,调用 sendto 函数往目标地址和端口发送 UDP 报文,然后客户端和服务器端进入互相应答过程。

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, 
          struct sockaddr *from, socklen_t *addrlen); 

ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,
                const struct sockaddr *to, socklen_t addrlen); 

sockfd、buff 和 nbytes 是前三个参数。sockfd 是本地创建的套接字描述符,buff 指向本地的缓存,nbytes 表示最大接收数据字节。
from 和 addrlen,实际上是返回对端发送方的地址和端口等信息,这和 TCP 非常不一样,TCP 是通过 accept 函数拿到的描述字信息来决定对端的信息。另外 UDP 报文每次接收都会获取对端的信息,也就是说报文和报文之间是没有上下文的。

本地套接字

本地套接字是一种特殊类型的套接字,和 TCP/UDP 套接字不同。TCP/UDP 即使在本地地址通信,也要走系统网络协议栈,而本地套接字,严格意义上说提供了一种单主机跨进程间调用的手段,减少了协议栈实现的复杂度,效率比 TCP/UDP 套接字都要高许多。类似的 IPC 机制还有 UNIX 管道、共享内存和 RPC 调用等。
创建的套接字类型,注意是 AF_LOCAL,并且使用字节流格式。TCP 的类型是 AF_INET 和字节流类型;UDP 的类型是 AF_INET 和数据报类型。
监听在一个本地文件路径标识的套接字上,本地文件路径,它必须是“绝对路径”,这样的话,编写好的程序可以在任何目录里被启动和管理。在 TCP 编程中,使用的是服务器的 IP 地址和端口作为目标,在本地套接字中则使用文件路径作为目标标识。
本地套接字的编程接口和 IPv4、IPv6 套接字编程接口是一致的,可以支持字节流和数据报两种协议。本地套接字的实现效率大大高于 IPv4 和 IPv6 的字节流、数据报套接字实现。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-12-09 12:04:23  更:2021-12-09 12:05:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 4:19:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码