网络编程简介

299 阅读14分钟

网络编程就是通过网络让不同计算机上运行的程序可以进行通信

一、 软件开发架构

两个程序之间通讯的应用大致可以分为两种:

第一种是应用类程序:qq、微信、网盘、优酷这一类是属于需要安装的桌面应用

第二种是 web 类程序:用户只需要浏览器即可访问程序,常见的 web 类应用程 序比如百度、知乎、CSDN 等使用浏览器访问就可以直接使用,不管是应用类程序还是 web 类程序,这些应用的本质其实都是两个程序之间的通讯,而这两个分类又对应了两个软件开发的架构

客户端服务端概念:

客户端:就是我们常用的程序例如 qq、微信,浏览器等等

服务端:要一直运行着给别人提供服务的机器(电脑、服务器), 例如现在我使用我的电脑就是服务端(服务器)

C/S 架构:

C/S 即:Client 与 Server ,中文意思:客户端与服务器端架构

这里的客户端一般泛指客户端应用程序 exe,程序需要先安装后,才能运行在用 户的电脑上,对用户的电脑操作系统环境依赖较大

B/S 架构:

B/S 即:Browser 与 Server,中文意思:浏览器端与服务器端架构, 只需在浏览器上通过 HTTP 去请求服务器端相关的资源(网页资源)

二、 计算机网络

首先说明一下每台电脑在网络世界中都有一个全球唯一的标识就是 ip 地址

那 ip 地址是什么呢?我们的电脑上网需要有硬件设施网线和网卡,网卡用来链接网线,网卡上有全球上唯一的物理地址(mac),长度为 48 位 2 进制,通常由 12 位 16 进制数表示(前六位是厂商编号,后六位是流水线号)

查看ip地址:ipconfig /all

一个 ip 地址通常写成四段十进制数,例:172.16.10.1

通过 ip 地址 就能找到 mac 地址,中间遵循了 ARP(Address Resolution Protocol) 协议, 中文叫:地址解析协议, 是根据 IP 地址获取物理地址的一个 TCP/IP 协议

一个特殊的地址 127.0.0.1 本地回环地址,访问自己电脑上的程序

0.0.0.0表示让所有ip地址都能访问

我们通过了 ip 地址找到了具体的某一台电脑,那我们怎么找到了想访问的应用呢?

例如两台 QQ 进行聊天案例,怎样找到另外一台电脑上的 QQ 程序呢?就需要通过电脑上的端口了

电脑上的每一个应用程序想运行必须占一个端口号,并且端口号同时间只能被一 个应用程序占用

每一台电脑上一共有 65536 个端口,端口的范围是 065535。一般 01023 被一 些其他应用已经占用,因此我们一般从 1024 开始指定端口

1、局域网

局域网(Local Area Network) ,简称 LAN,是指在某一区域内由多台计算机互联 成的计算机组。“某一区域”指的是同一办公室、同一建筑物、同一公司和同一 学校等,一般是方圆几千米以内。局域网可以实现文件管理、应用软件共享、打 印机共享、扫描仪共享、工作组内的日程安排、电子邮件和传真通信服务等功能。 局域网是封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的 上千台计算机组成

2、广域网

广域网(Wide Area Network),简称 WAN,是一种跨越大的、地域性的计算机网 络的集合。通常跨越省、市,甚至一个国家,广域网包括大大小小不同的子网, 子网可以是局域网,也可以是小型的广域网

3、局域网和广域网的区别

局域网是在某一区域内的,而广域网要跨越较大的地域,那么如何来界定这个区 域呢?例如,一家大型公司的总公司位于北京,而分公司遍布全国各地,如果该 公司将所有的分公司都通过网络联接在一起,那么一个分公司就是一个局域网, 而整个总公司网络就是一个广域网

三、网络协议(TCP/IP 协议族)

网络协议就是为了能让计算机网络中进行数据交换而建立的规则、标准

例如下载软件然后如果不同意协议就不能继续下一步,同样的道理在互联网中, 如果不遵循互联网协议就不能访问到资源

互联网上有上百种协议,但是最重要的两个协议是 TCP 协议和 IP 协议,因此我们将上百种协议统称为 TCP/IP 协议族,TCP/IP 协议族,根据协议的功能的不同 抽象成了 4 层

应用层:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等

传输层:TCP,UDP

网络层:IP,ICMP,OSPF,EIGRP,IGMP

数据链路层:SLIP,CSLIP,PPP,MTU

数据传输的时候先将数据从应用层传递到传输层,然后再从传输层传递到网络 层,然后再传递到链路层,最后在通过物理传输介质(网线)传递数据。大家想一 下为什么要一层一层的传递,而不是直接传递数据呢?是为了保证数据能够稳定 的传输到对方电脑上去

我们电脑上的数据想要发生到你的电脑上需要通过一层一层的传 输,在传输过程中为了保证数据不丢失,需要在每一层的时候添加一些额外的内 容。那每一层都添加了哪些内容呢?

例如 应用层指的是 QQ 通信需要有自己的协议,迅雷下载下载东西有自己的协议,浏览器访问互联网使用的是 HTTP协议

例如现在发送一个‘hello’走的过程是:

(1)在应用层加上自己的协议 例如 xx hello

(2)传递到了传输层,添加了源端口和目的端口

(3)走到了网络层,会在前面添加上 源 ip 地址和目的 ip

(4)走到链路层,添加源 mac 地址和目的 mac 地址

然后通过网线传输到对方的电脑上,先判断是不是我的 mac 地址,如果是就减去 mac,在往上到网络层,判断是不是我的 ip 地址,如果是就减去,依次往上走, 直到 qq,中间如果有一层不对就把数据扔掉。对方就不能获取发送过来的信息

四、TCP 协议

TCP(Transmission Control Protocol)可靠的、面向连接的协议 (什么是面向连接呢?就是发送消息之前先建立连接然后再发送消息例如打电话 场景,在网络中具体指的是三次握手)

TCP 协议特点:数据安全,速度略低。分为客户端和服务端

使用 TCP 的应用:Web 浏览器;电子邮件等程序

TCP 的三次握手和 4 次挥手

TCP报文类型:SYN/ACK

SYN(连接请求信号):同步序列编号(Synchronize Sequence Numbers)是TCP/IP建立连接时使用的握手信号,TCP连接的第一个包,非常小的一种数据包

ACK(应答信号):确认标识(Acknowledge character)是对所收到的报文进行检查,若未发现错误,便向对方发出确认回答ACK信号,表明信息已被正确接收,并准备好接收下一份报文

**TCP 三次握手: **

TCP 是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出 SYN 连接请求后等待对方回答 SYN+ACK[1],并最终对对方的 SYN 执行 ACK 确认。 这种建立连接的方法可以防止产生错误的连接

TCP 三次握手的过程如下:

(1)客户端发送 SYN(SEQ=x)报文给服务器端,进入 SYN_SEND 状态

(2)服务器端收到SYN报文,回应一个SYN(SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV 状态

(3)客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established 状态

三次握手完成,TCP 客户端和服务器端成功地建立连接,可以开始传输数据了

数据传输: 每传递一次消息,服务端都会告诉客户端说收到消息了,这样确保数据不会丢失,因此我们说 TCP 是可靠地面向连接(连接一直连着)的传输协议

TCP四次挥手:

建立一个连接需要三次握手,而终止一个连接要经过四次挥手

TCP四次挥手的过程如下:

(1) 某个应用进程首先调用 close,称该端执行“主动关闭”(active close),该端的 TCP 于是发送一个 FIN 分节,表示数据发送完毕

(2) 接收到这个 FIN 的对端执行 “被动关闭”(passive close),这个 FIN 由 TCP 确认

注意:FIN 的接收也作为一个文件结束符(end-of-file)传递给接收端应用进 程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN 的接收意 味着接收端应用进程在相应连接上再无额外数据可接收

(3) 一段时间后,接收到这个文件结束符的应用进程将调用 close 关闭它的套接字,这导致它的 TCP 也发送一个 FIN

(4) 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN

五、UDP 协议

UDP 协议: 面向无连接,数据不安全,速度快,不区分客户端与服务端

用于网络电话,在线视频网络会议等等,要求实时性比较高(数据传输快)不能有延迟

当应用程序希望通过 UDP 与一个应用程序通信时,传输数据之前源端和终端不建立连接

当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上

因此 UDP 是不可靠无连接的协议,因为有可能数据会丢失

六、TCP 和 UDP 的对比

TCP--提供的是面向连接、可靠的服务,当客户和服务器彼此交换数据前,必须先在双方之间建立一个 TCP 连接,之后才能传输数据,TCP 提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端

UDP--是一个简单的不可靠的运输层协议,它只是把应用程序传给 IP 层的数据报 发送出去,但是并不能保证它们能到达目的地,由于 UDP 在传输数据报前不用在 客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快

七、OSI 模型

OSI 模型是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联的 标准体系,一般称为 OSI 参考模型或七层模型

OSI 模型又将 TCP/IP 协议族的四层进行了具体划分,划分成了 7 层

八、socket

1、理解 Socket

首先我们写的网络编程,属于应用层,当我们写好了程序后,需要将数据发送给运输层,但是应用层和运输层通信需要遵循相关协议,关键是我们不了解运输层的协议, 那该怎么办呢?因此提供了 Socket 层,Socket 英文插座,插口,套接字意思

Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层,它把复杂的 TCP/IP 协 议族隐藏在 Socket 接口后面,对用户来说,让 Socket 去组织数据,以符合指定 的协议。(面向对象的特点,我们只负责编写逻辑即可,不用去管 TCP/IP 具体的 格式,Sockect 会帮我们做)

2、socket 发展史

套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,有时 人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设 计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC

套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的

(1)基于文件型: 套接字家族的名字:AF_UNIX unix 一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个 套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

(2)基于网络型: 套接字家族的名字:AF_INET (还有 AF_INET6 被用于 ipv6,还有一些其他的地址家族,不过,他们要么是只用 于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现, 所有地址家族中,AF_INET 是使用最广泛的一个,python 支持很多种地址家族, 但是由于我们只关心网络编程,所以大部分时候我么只使用 AF_INET)

(3)socket 参数详解

socket.socket(family=AF_INET,type=SOCK_STREAM)

参数说明
family地址系列应为 AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN 或 AF_RDS, (AF_UNIX 域实际上是使用本地 socket 文件来通信)
type套接字类型应为 SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW 或其他 SOCK_常量之一,SOCK_STREAM 是基于 TCP 的,有保障的(即能保证数据正确传送到对方)面向连接的 SOCKET, 多用于资料传送SOCK_DGRAM 是基于 UDP 的,无保障的面向消息的 socket,多用于在网络上发广播信息

3、基于 TCP 协议的 Socket 使用

Socket 是基于 tcp 协议的,tcp 是基于链接的,因此在通讯开始之前,一定要先建立相关的链接,才能发送数据,必须先启动服务端,然后再启动客户端去链接服务端

4、基于 UDP 协议的 Socket 使用

udp 是无链接的,启动服务之后可以直接接受消息,不需要提前建立链接

九、案例:QQ 聊天室

服务端:

import socket

udp_sk = socket.socket(type=socket.SOCK_DGRAM)
udp_sk.bind(('127.0.0.1', 9999))
while True:
    msg, addr = udp_sk.recvfrom(1024)
    print(msg.decode('utf-8'))
    info = input('>>>server:').encode('utf-8')
    udp_sk.sendto(info, addr)

udp_sk.close()

客户端:

import socket

udp_sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ('127.0.0.1', 9999)
while True:
    msg = input('>>>one说:')
    udp_sk.sendto(msg.encode('utf-8'), ip_port)
    ret, addr = udp_sk.recvfrom(1024)
    print('服务端返回信息-->', ret.decode('utf-8'))

udp_sk.close()

九、urllib 网络请求模块

urllib 库的基本使用 所谓网络请求,就是把 URL 地址中指定的网络资源从网络流中读取出来,保存 到本地。 在 python 中有很多库可以用来获取网络资源,我们先学习 urllib

代码实现:

from urllib import request

# 定义目标url

base_url = 'http://www.baidu.com'

# 发起一个Get类型请求
# 向指定的url发送请求,并返回服务器响应的文件对象
response = request.urlopen(url=base_url)

# 类文件对象支持文件对象的操作方法,如read()方法读取文件全部内容,返回字符串
html = response.read().decode('utf-8')  # 读取btyes类型,转成str类型

# 打印字符串
print(html)

# 对内容进行文件保存
with open('百度.html', 'w', encoding='utf-8') as f:
    f.write(html)

实际上,如果我们在浏览器上打开百度主页, 右键选择“查看源代码”,你会发 现,跟我们刚才打印出来的是一模一样,也就是说,上面的 4 行代码就已经帮我 们把百度的首页的全部代码爬了下来