全栈必备——网络编程基础

news2024/11/23 3:22:45

我们是幸运的,因为我们拥有网络。网络是一个神奇的东西,它改变了你和我的生活方式,改变了整个世界。 然而,网络的无标度和小世界特性使得它又是复杂的,无所不在,无所不能,以致于我们无法区分甚至无法描述。

对于一个码农而言,了解网络的基础知识可能还是从了解定义开始,认识OSI的七层协议模型,深入Socket内部,进而熟练地进行网络编程。

关于网络

关于网络,在词典中的定义是这样的:

在电的系统中,由若干元件组成的用来使电信号按一定要求传输的电路或这种电路的部分,叫网络。

作为一名从事过TMN开发的通信专业毕业生,固执地认为网络是从通信系统中诞生的。通信是人与人之间通过某种媒介进行的信息交流与传递。传统的通信网络(即电话网络)是由传输、交换和终端三大部分组成,通信网络是指将各个孤立的设备进行物理连接,实现信息交换的链路,从而达到资源共享和通信的目的。通信网络可以从覆盖范围,拓扑结构,交换方式等诸多视角进行分类…… 满满的回忆,还是留在书架上吧。

网络的概念外延被不断的放大着,抽象的思维能力是人们创新乃至创造的根源。网络用来表示诸多对象及其相互联系,数学上的图,物理学上的模型,交通网络,人际网络,城市网络等等,总之,网络被总结成从同类问题中抽象出来用数学中的图论科学来表达并研究的一种模型。

很多伙伴认为,了解这些之后呢,然并卵。我们关心的只是计算机网络,算机网络是用通信线路和设备将分布在不同地点的多台计算机系统互相连接起来,按照网络协议,分享软硬件功能,最终实现资源共享的系统。特别的,我们谈到的网络只是互联网——Internet,或者移动互联网,需要的是写互联网应用程序。但是,一位工作了五六年的编程高手曾对我说,现在终于了解到基础知识有多重要,技术在不断演进,而相对不变的就是那些原理和编程模型了。

老码农深以为然,编程实践就是从具体到抽象,再到具体,循环往复,螺旋式上升的过程。了解前世今生,只是为了可能触摸到“势”。基础越扎实,建筑就会越有想象的空间。 对于网络编程的基础,大概要从OSI的七层协议模型开始了。

c/c++ Linux服务器开发,音视频开发高阶视频,文档资料后台私信【架构】获取

七层模型

七层模型(OSI,Open System Interconnection参考模型),是参考是国际标准化组织制定的一个用于计算机或通信系统间互联的标准体系。它是一个七层抽象的模型,不仅包括一系列抽象的术语和概念,也包括具体的协议。 经典的描述如下:

简述每一层的含义:

  1. 物理层(Physical Layer):建立、维护、断开物理连接。
  2. 数据链路层 (Link):逻辑连接、进行硬件地址寻址、差错校验等。
  3. 网络层 (Network):进行逻辑寻址,实现不同网络之间的路径选择。
  4. 传输层 (Transport):定义传输数据的协议端口号,及流控和差错校验。
  5. 会话层(Session Layer):建立、管理、终止会话。
  6. 表示层(Presentation Layer):数据的表示、安全、压缩。
  7. 应用层 (Application):网络服务与最终用户的一个接口

每一层利用下一层提供的服务与对等层通信,每一层使用自己的协议。了解了这些,然并卵。但是,这一模型确实是绝大多数网络编程的基础,作为抽象类存在的,而TCP/IP协议栈只是这一模型的一个具体实现。

TCP/IP 协议模型

TCP/IP是Internet的基础,是一组协议的代名词,包括许多协议,组成了TCP/IP协议栈。TCP/IP 有四层模型和五层模型之说,区别在于数据链路层是否作为独立的一层存在。个人倾向于5层模型,这样2层和3层的交换设备更容易弄明白。当谈到网络的2层或3层交换机的时候,就知道指的是那些协议。

数据是如何传递呢?这就要了解网络层和传输层的协议,我们熟知的IP包结构是这样的:

P协议和IP地址是两个不同的概念,这里没有涉及IPV6的。不关注网络安全的话,对这些结构不必耳熟能详的。传输层使用这样的数据包进行传输,传输层又分为面向连接的可靠传输TCP和数据包UDP。TCP的包结构:

TCP 连接建立的三次握手肯定是必知必会,在系统调优的时候,内核中关于网络的相关参数与这个图息息相关。UDP是一种无连接的传输层协议,提供的是简单不可靠的信息传输。协议结构相对简单,包括源和目标的端口号,长度以及校验和。基于TCP和UDP的数据封装及解析示例如下:

还是然并卵么?一个数据包的大小了解了,会发现什么?PayLoad到底是多少?在设计协议通信的时候,这些都为我们提供了粒度定义的依据。进一步,通过一个例子看看吧。

模型解读示例

FTP是一个比较好的例子。为了方便起见,假设两条计算机分别是A 和 B,将使用FTP 将A上的一个文件X传输到B上。

首先,计算机A和B之间要有物理层的连接,可以是有线比如同轴电缆或者双绞线通过RJ-45的电路接口连接,也可以是无线连接例如WIFI。先简化一下,考虑局域网,暂不讨论路由器和交换机以及WIFI热点。这些物理层的连接建立了比特流的原始传输通路。

接下来,数据链路层登场,建立两台计算机的数据链路。如果A和B所在的网络上同时连接着计算机C,D,E等等,A和B之间如何建立的数据链路呢?这一过程就是物理寻址,A要在众多的物理连接中找到B,依赖的是计算机的物理地址即MAC地址,对就是网卡上的MAC地址。以太网采用CSMA/CD方式来传输数据,数据在以太网的局域网中都是以广播方式传输的,整个局域网中的所有节点都会收到该帧,只有目标MAC地址与自己的MAC地址相同的帧才会被接收。A通过差错控制和接入控制找到了B的网卡,建立可靠的数据通路。

那IP地址呢? 数据链路建立起来了,还需要IP地址么?我们FTP 命令中指定的是IP地址而不是MAC地址呀?IP地址是逻辑地址,包括网络地址和主机地址。如果A和B在不同的局域网中,中间有着多个路由器,A需要对B进行逻辑寻址才可以的。物理地址用于底层的硬件的通信,逻辑地址用于上层的协议间的通信。在以太网中:逻辑地址就是IP地址,物理地址就是MAC 地址。在使用中,两种地址是用一定的算法将他们两个联系起来的。所以,IP是用来在网络上选择路由的,在FTP的命令中,IP中的原地址就是A的IP地址,目标地址就是B的IP地址。这应该就是网络层,负责将分组数据从源端传输到目的端。

A向B传输一个文件时,如果文件中有部分数据丢失,就可能会造成在B上无法正常阅读或使用。所以需要一个可靠的连接,能够确保传输过程的完整性,这就是传输层的TCP协议,FTP就是建立在TCP之上的。TCP的三次握手确定了双方数据包的序号、最大接受数据的大小(window)以及MSS(Maximum Segment Size)。TCP利用IP完成寻址,TCP中的提供了端口号,FTP中目的端口号一般是21。传输层的端口号对应主机进程,指本地主机与远程主机正在进行的会话。

会话层用来建立、维护、管理应用程序之间的会话,主要功能是对话控制和同步,编程中所涉及的session是会话层的具体体现。表示层完成数据的解编码,加解密,压缩解压缩等,例如FTP中bin命令,代表了二进制传输,即所传输层数据的格式。 HTTP协议里body中的Json,XML等都可以认为是表示层。应用层就是具体应用的本身了,FTP中的PUT,GET等命令都是应用的具体功能特性。

简单地,物理层到电缆连接,数据链路层到网卡,网络层路由到主机,传输层到端口,会话层维持会话,表示层表达数据格式,应用层就是具体FTP中的各种命令功能了。

Socket

了解了7层模型就可以编程了么,拿起编程语言就可以耍了么?刚开始上手尝试还是可以的,如果要进一步,老码农觉得还是看看底层实现的好,因为一切归根到底都会归结为系统调用。到了操作系统层面如何看网络呢?Socket登场了。

在Linux世界,“一切皆文件”,操作系统把网络读写作为IO操作,就像读写文件那样,对外提供出来的编程接口就是Socket。所以,socket(套接字)是通信的基石,是支持TCP/IP协议网络通信的基本操作单元。socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。一个完整的socket有一个本地唯一的socket号,这是由操作系统分配的。

从设计模式的角度看, Socket其实是一个外观模式,它把复杂的TCP/IP协议栈隐藏在Socket接口后面,对用户来说,一组简单的Socket接口就是全部。当应用程序创建一个socket时,操作系统就返回一个整数作为描述符(descriptor)来标识这个套接字。然后,应用程序以该描述符为传递参数,通过调用函数来完成某种操作(例如通过网络传送数据或接收输入的数据)。以TCP 为例,典型的Socket 使用如下:

在许多操作系统中,Socket描述符和其他I/O描述符是集成在一起的,操作系统把socket描述符实现为一个指针数组,这些指针指向内部数据结构。进一步看,操作系统为每个运行的进程维护一张单独的文件描述符表。当进程打开一个文件时,系统把一个指向此文件内部数据结构的指针写入文件描述符表,并把该表的索引值返回给调用者 。

既然Socket和操作系统的IO操作相关,那么各操作系统IO实现上的差异会导致Socket编程上的些许不同。看看我Mac上的Socket.so 会发现和CentOS上的还是些不同的。

在许多操作系统中,Socket描述符和其他I/O描述符是集成在一起的,操作系统把socket描述符实现为一个指针数组,这些指针指向内部数据结构。进一步看,操作系统为每个运行的进程维护一张单独的文件描述符表。当进程打开一个文件时,系统把一个指向此文件内部数据结构的指针写入文件描述符表,并把该表的索引值返回给调用者 。

既然Socket和操作系统的IO操作相关,那么各操作系统IO实现上的差异会导致Socket编程上的些许不同。看看我Mac上的Socket.so 会发现和CentOS上的还是些不同的。

进程进行Socket操作时,也有着多种处理方式,如阻塞式IO,非阻塞式IO,多路复用(select/poll/epoll),AIO等等。

多路复用往往在提升性能方面有着重要的作用。select系统调用的功能是对多个文件描述符进行监视,当有文件描述符的文件读写操作完成以及发生异常或者超时,该调用会返回这些文件描述符。select 需要遍历所有的文件描述符,就遍历操作而言,复杂度是 O(N)。

epoll相关系统调用是在Linux 2.5 后的某个版本开始引入的。该系统调用针对传统的select/poll不足,设计上作了很大的改动。select/poll 的缺点在于:

  1. 每次调用时要重复地从用户模式读入参数,并重复地扫描文件描述符。
  2. 每次在调用开始时,要把当前进程放入各个文件描述符的等待队列。在调用结束后,又把进程从各个等待队列中删除。

epoll 是把 select/poll 单个的操作拆分为 1 个 epoll_create,多个 epoll_ctrl和一个 wait。此外,操作系统内核针对 epoll 操作添加了一个文件系统,每一个或者多个要监视的文件描述符都有一个对应的inode 节点,主要信息保存在 eventpoll 结构中。而被监视的文件的重要信息则保存在 epitem 结构中,是一对多的关系。由于在执行 epoll_create 和 epoll_ctrl 时,已经把用户模式的信息保存到内核了, 所以之后即便反复地调用 epoll_wait,也不会重复地拷贝参数,不会重复扫描文件描述符,也不反复地把当前进程放入/拿出等待队列。

所以,当前主流的Server侧Socket实现大都采用了epoll的方式,例如Nginx, 在配置文件可以显式地看到 use epoll。

网络编程

了解了7层协议模型和操作系统层面的Socket实现,可以方便我们理解网络编程。

在系统架构的时候,有重要的一环就是拓扑架构,这里涉及了网络等基础设施,那么7层协议下四层就会有助于我们对业务系统网络结构的观察和判断。在系统设计的时候,往往采用面向接口的设计,而接口也往往是基于HTTP协议的Restful API。 那接口的粒度就可以将data segment作为一个约束了,同时可以关注到移动互联网中的弱网环境。

不同的编程语言,有着不同的框架和库,真正的编写网络程序代码并不复杂,例如,用Erlang 中 gen_tcp 用于编写一个简单的Echo服务器:

Start_echo_server()->
         {ok,Listen}= gen_tcp:listen(1234,[binary,{packet,4},{reuseaddr,true},{active,true}]),
         {ok,socket}=get_tcp:accept(Listen),
         gen_tcp:close(Listen),
         loop(Socket).

loop(Socket) ->
         receive
                  {tcp,Socket,Bin} ->
                            io:format(“serverreceived binary = ~p~n”,[Bin])
                            Str= binary_to_term(Bin),
                            io:format(“server  (unpacked) ~p~n”,[Str]),
                            Reply= lib_misc:string2value(Str),
                            io:format(“serverreplying = ~p~n”,[Reply]),
                            gen_tcp:send(Socket,term_to_binary(Reply)),
                            loop(Socket);
                   {tcp_closed,Socket} ->
                            Io:format(“ServerSocket closed ~n”)
         end.

然而,写出漂亮的服务器程序仍然是一件非常吃功夫的事情,例如,个人非常喜欢的python Tornado 代码, 在ioloop.py 中有对多路复用的选择:

@classmethod
def configurable_default(cls):
        if hasattr(select, "epoll"):
            from tornado.platform.epoll import EPollIOLoop
            return EPollIOLoop
        if hasattr(select, "kqueue"):
            # Python 2.6+ on BSD or Mac
            from tornado.platform.kqueue import KQueueIOLoop
            return KQueueIOLoop
        from tornado.platform.select import SelectIOLoop
        return SelectIOLoop

在HTTPServer.py 中同样继承了TCPServer,进而实现了HTTP协议,代码片段如下:

class HTTPServer(TCPServer, Configurable,
                httputil.HTTPServerConnectionDelegate):
                ...
    def initialize(self, request_callback, no_keep_alive=False, io_loop=None,
                   xheaders=False, ssl_options=None, protocol=None,
                   decompress_request=False,
                   chunk_size=None, max_header_size=None,
                   idle_connection_timeout=None, body_timeout=None,
                   max_body_size=None, max_buffer_size=None):
        self.request_callback = request_callback
        self.no_keep_alive = no_keep_alive
        self.xheaders = xheaders
        self.protocol = protocol
        self.conn_params = HTTP1ConnectionParameters(
            decompress=decompress_request,
            chunk_size=chunk_size,
            max_header_size=max_header_size,
            header_timeout=idle_connection_timeout or 3600,
            max_body_size=max_body_size,
            body_timeout=body_timeout)
        TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,
                           max_buffer_size=max_buffer_size,
                           read_chunk_size=chunk_size)
        self._connections = set()
        ...

或许,老码农说的都是错的,了解了所谓的网络基础,也不一定写出漂亮的代码,不了解所谓的网络基础,也不一定写不出漂亮的代码,全当他自言自语吧。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1306598.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

镭速助力集成绘图建模工具加速文件传输速度

在当前信息化社会中,绘图建模工具已经成为许多人不可或缺的伙伴。无论是学习、工作还是生活,这些工具都能够在表达思想、设计方案以及展示成果等方面发挥重要作用。然而,随着绘图建模工具功能的日益强大,用户创作的文件也变得越来…

基于ssm大学生创新创业平台项目管理子系统设计与实现论文

摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对大学生创新创业项目信息管理混乱,出错率高,信…

js基础:简介、变量与数据类型、流程循环控制语句、数组及其api

JS基础:简介、变量与数据类型、流程循环控制语句、数组及其api 一、简介 1、js概述 tip:JavaScript是什么? 有什么作用? JavaScript(简称JS)是一种轻量级的、解释性的编程语言,主要用于在网页…

java系列-LinkedHashMap怎么实现LRU

1.定义变量accessOrder public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {final boolean accessOrder;public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {super(initialCapacity, loadFactor…

小间距LED显示屏的芯片扮演的关键角色

LED屏幕由数万颗灯珠封装而成&#xff0c;包含驱动芯片、PCB板、电阻、电容、模组套件和箱体等&#xff0c;形成一块高清LED显示屏。芯片的质量直接影响整个屏幕的品质、稳定性和性能。那么&#xff0c;什么是细间距LED显示屏&#xff1f;小间距LED显示屏芯片具体有何作用呢&am…

设计模式(2)--对象创建(1)--抽象工厂

1. 意图 提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。 2. 四种角色 抽象产品(Product)、具体产品(Concrete Product)、抽象工厂(Abstract Factory)、具体工厂(Concrete Factory)。 3. 优点 3.1 分离了具体的类。Client只需使用抽象工厂类…

易生支付与青岛国资之间的合作即将成为现实。青岛国资决定以曲线入股易生支付。

易生金服的次要股权可能会有新的控制方。 根据西米支付网的消息&#xff0c;经营支付服务的持牌机构“易生支付”的唯一股东“易生金服”的第二大股东凯撒同盛发展股份有限公司的控股权将转让给青岛环海湾文化旅游发展有限公司&#xff0c;同时实际控制权也将交由青岛市市北区国…

java ATM swing窗体转账,取款,存款等

ATM 转账&#xff0c;取款&#xff0c;存款等等 开发环境 开发语言为Java&#xff0c;开发环境Eclipse或者IDEA都可以。 系统框架 利用JDK自带的 框架开发&#xff0c; 纯窗体模式&#xff0c;直接运行Main文件即可以。 涉及主要技术 银行ATM系统 系统用Java语言编写&a…

抖店做起来到底有多难?带你揭露抖音电商的真相!

我是电商珠珠 无论是谁问抖店还能做吗&#xff1f;基本上答案都是肯定的。他们只会说做店很简单&#xff0c;而不会告诉你做电商的压力&#xff0c;以及最真实的投资。 做抖店的风险他们都是一笔带过&#xff0c;好像无论是谁都能做一样。大部分电商公司都会让你做无货源&…

火力发电厂防雷及浪涌防护解决方案

火力发电厂是一种利用燃料燃烧产生的热能驱动汽轮机发电的设施&#xff0c;是目前世界上最常见的发电方式之一。火力发电厂的运行需要大量的电气设备&#xff0c;如辅机马达、通信系统、MIS系统、DCS系统等&#xff0c;这些设备对雷电分敏感&#xff0c;特别是DCS系统&#xff…

如何实现nacos的配置的热更新

我们在使用nacos进行修改配置后&#xff0c;需要微服务无需重启即可让配置生效&#xff0c;也就是使配置进行热更新我们可以采用下面的两种方式进行配置的热更新操作 方式一&#xff1a;在Value所注入的变量的类上添加注解RefreshScope RestController RequestMapping("/o…

Kubernetes(k8s)集群部署----->超详细

Kubernetes&#xff08;k8s&#xff09;集群部署-----&#xff1e;超详细 一、资源准备二、安装准备2.1 主机环境设置2.1.1 关闭操作系统防火墙、selinux2.1.2 关闭swap交换分区2.1.3 允许iptables检测桥接流量&#xff08;可选&#xff09; 2.2 安装Docker环境2.3 安装Kubeadm…

34、卷积实战 - 手写一个基础卷积算法

前面基本上把卷积这一算法的原理和公式介绍完了,如果还有不懂的,可以多翻几遍前面的章节内容,深入理解一下。 本节加一个实战,大家可以手动来实现一个卷积算法,本文中以 python 代码为例,C++ 的代码可以查看本节后面的链接。 说到卷积实现,其实就是自己手写一个卷积算…

pycharm中py文件设置参数

在py文件中右键 直接对应复制进去即可

python matplotlib set_aspect

说明: # 设置轴比例相等&#xff0c;以获得圆柱体视角 ax.set_aspect(equal) 代码案例: import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np# 创建数据 theta np.linspace(0, 2*np.pi, 100) z np.linspace(0, 1, 100) r z**2 …

Llama2-Chinese-7b-Chat安装部署

文章目录 前言一、文件介绍 &#x1f4c1;二、环境配置 ♟三、Llama2-Chinese-7b-Chat下载 ⏬总结 前言 本文主要介绍如何使用Llama2-Chinese-7b-Chat&#xff0c;最后的效果如图所示&#xff1a; 一、文件介绍 &#x1f4c1; ⬇️ 下载地址&#xff1a;https://pan.baidu.…

Facebook运营技巧详解,Facebook多店铺如何运营?

在前不久的文章中就讲过Facebook养号和广告的投放技巧&#xff0c;今天东哥就趁热打铁来接着讲讲Facebook的运营技巧&#xff0c;现在做外贸和跨境电商的人基本上都用过Facebook&#xff0c;像在流量这么庞大的平台上想要抓住更多机遇&#xff0c;懂得一些运营技巧是必不可少的…

室内空气污染愈演愈烈,新风系统如何实现呼吸自由

室内空气污染到底有多可怕&#xff1f;有研究发现&#xff0c;室内空气污染比室外空气污染严重2~3倍&#xff0c;甚至几十倍&#xff0c;我国每年有11.1万人因室内空气污染死亡&#xff0c;全球更是高达430万人&#xff0c;68%的人体疾病与室内污染有关&#xff0c;90%的白血病…

c++线程同步之条件变量

c线程同步之条件变量 ​ 条件变量是C11提供的另外一种用于等待的同步机制&#xff0c;它能阻塞一个或多个线程&#xff0c;直到收到另外一个线程发出的通知或者超时时&#xff0c;才会唤醒当前阻塞的线程。条件变量需要和互斥量配合起来使用&#xff0c;C11提供了两种条件变量…

Linux --绘制地图投影出现报错:无法成功下载地图背景数据

Linux --绘制地图投影出现报错&#xff1a;无法成功下载地图背景数据 主要原因是由于使用学院集群&#xff0c;该集群无法连接外网&#xff0c;在使用cartopy绘制地图投影时&#xff0c;导致无法成功加载地图背景数据解决方法也很简单&#xff0c;自己手动下载所需要的地形数据…