基础知识、OSI模型、TCP/IP模型、UDP套接字编程
- 网络并发编程
- 1. 网络编程
- 1.1 网络基础知识
- OSI 7层模型(Open System Interconnection)即开放式系统互联
- *** 面试时如何答诸如“请谈一下OSI七层模型”这样的理论问题?
- TCP/IP模型 (实际工作模型)
- 关于网络协议
- 1.1.3 通信地址
- 关于公网IP和内网IP
- 公网IP指的是连接到互联网上的公共IP地址,大家都可以访问。(将来进公司,公司会申请公网IP作为网络项目的被访问地址)
- 内网IP指的是一个局域网络范围内由网络设备分配的IP地址。
- 解惑:
- a. 同一个网段内的IP地址是可以重复的
- b. 使用内网IP地址在不同局域网下是不可通信的
- c. 公网IP是不能直接访问内网IP的,只能是内网IP主动访问公网IP
- 端口与端口号
- 端口:网络地址的一部分,在一台计算机上,每个网络程序对应一个端口。
- 端口号特点
- 1.1.4 服务端与客户端 常见两种服务端客户端结构:
- C/S结构 -> Client/Server B/S结构 -> Browser/Server
- 1.2 UDP 传输方法(用户数据报协议)
- 1.2.3 UDP套接字编程
网络并发编程
1. 网络编程
1.1 网络基础知识
历史背景:20世纪60年代末,美苏冷战与阿帕网[美国国防部的高级研究计划局(ARPA)]
1.1.1 什么是网络
- 什么是网络 : 计算机网络功能主要包括实现资源共享,实现数据信息的快速传递。
1.1.2 网络通信标准
-
面临的问题
- 不同的国家和公司都建立自己的通信标准不利于网络互连
- 多种标准并行情况下不利于技术的发展融合
OSI 7层模型(Open System Interconnection)即开放式系统互联
蓝色的3层是和应用工程师息息相关的,绿色的1-3层是硬件层,中间的传输层基本由操作系统实现(操作系统就是为连接软硬件而开发的),下层提供传输服务,上层根据需求作出相应选择
· 好处
- 建立了统一的通信标准
- 降低开发难度,每层功能明确,各司其职
- 七层模型实际规定了每一层的任务,该完成什么事情
https://www.cnblogs.com/qishui/p/5428938.html
*** 面试时如何答诸如“请谈一下OSI七层模型”这样的理论问题?
思路:这是什么 -> 具体描述 -> 特点(优点、缺点) -> 话题引申 -> 我用它做什么(可以把话题引到自己的项目经验上)
TCP/IP模型 (实际工作模型)
- 七层模型过于理想,结构细节太复杂
- 在工程中应用实践难度大
- 实际工作中以TCP/IP模型为工作标准流程
关于网络协议
-
什么是网络协议:在网络数据传输中,都遵循的执行规则。
-
网络协议实际上规定了每一层在完成自己的任务时应该遵循什么规范。
-
需要应用工程师做的工作 : 编写应用功能,明确对方地址,选择传输服务。
1.1.3 通信地址
-
IP地址
解惑:
a. 同一个网段内的IP地址是可以重复的
b. 使用内网IP地址在不同局域网下是不可通信的
c. 公网IP是不能直接访问内网IP的,只能是内网IP主动访问公网IP
-
端口号特点
-
取值范围: 0 —— 65535 的整数
-
一台计算机上的网络应用所使用的端口不会重复
-
并且只有在运行的网络程序才会占用端口
-
通常 0——1023 的端口会被一些有名的程序或者系统服务占用,个人一般使用 > 1024的端口
- e.g. MySQL在运行时默认会申请3306端口,如果在此之前已经有别的程序占用了3306,则必须分配其他可用的端口 MySQL才能正常运行
-
1.1.4 服务端与客户端 常见两种服务端客户端结构:
C/S结构 -> Client/Server B/S结构 -> Browser/Server
-
服务端(Server):服务端是为客户端服务的,服务的内容诸如向客户端提供资源,保存客户端数据,处理客户端请求等。
(服务端的程序端口往往都是固定的)
-
客户端(Client) :也称为用户端,是指与服务端相对应,为客户提供一定应用功能的程序,我们平时使用的手机或者电脑上的程序基本都是客户端程序。
1.2 UDP 传输方法(用户数据报协议)
1.2.1 套接字简介
-
套接字(Socket) : 实现网络编程进行数据传输的一种技术手段,网络上各种各样的网络服务大多都是基于 Socket 来完成通信的。
-
Python套接字编程模块:
import socket
1.2.3 UDP套接字编程
[UDP——User Datagram Protocol]
1.2.3.1 创建套接字
sockfd=socket.socket(family,type)
功能:创建套接字
参数:family 网络地址类型 AF_INET表示ipv4
type 套接字类型 SOCK_DGRAM 表示udp套接字 (也叫数据报套接字)
返回值: 套接字对象
## 注:第一个参数family的默认值就是AF_INET,
## 所以在创建udp套接字对象时也可以写:
对象名 = socket.socket(type=socket.SOCK_DGRAM)
1.2.3.2 绑定地址(通常情况下由服务端完成,因为没人关心客户端的地址是什么,客户端通常也就不绑定特定的地址了)
- 本地地址 : ‘localhost’ , ‘127.0.0.1’ 绑定本地测试IP
- 网络地址 : ‘172.40.91.185’ (通过ifconfig查看)
- 自动获取地址: ‘0.0.0.0’ (相当于以上两种功能的总和)
sockfd.bind(addr)
功能: 绑定本机网络地址
参数: 二元元组 (ip,port) ('0.0.0.0',8888)
注意:socket模块中存储网络地址都是以元组形式存储的,其中ip地址用字符串形式,端口号则是整数类型
1.2.3.3 消息收发
收: recvfrom()
data,addr = sockfd.recvfrom(buffersize)
功能: 接收UDP消息
参数: 每次最多接收多少字节
返回值: data 接收到的内容
addr 消息发送方地址(元组形式)
发:sendto()
n = sockfd.sendto(data,addr)
功能: 发送UDP消息
参数: data 发送的内容 bytes格式
addr 目标地址(同样是元组形式)
返回值:**发送的字节数**
注意:
1. socket的收发内容都以字节为基本单位
2. 客户端访问服务端时,地址和端口必须与服务器一致
** 一个有趣的问题:服务器在创建套接字对象后,通常先接收还是先发送?
——自然是先接收。由于客户端连接的都是内网IP,而服务端通常是公网IP,公网IP是不能主动访问内网IP的,即使我们的设备在使用过程中突然弹出一个窗口,那也是设备上安装的某些垃圾插件主动通过内网IP向服务端发送了内容,而发送内容中包含着发送方地址,服务端接收到内容之后,再把弹窗定向精准发送到我们的设备上
1.2.3.4 关闭套接字
sockfd.close()
功能:关闭套接字
recvfrom()函数是阻塞函数 - - 相关延伸:
阻塞函数:即在调用时产生“程序阻塞”效果,在满足一定条件后继续运行,例如input()、sleep(),recvfrom()也是阻塞函数,它在等接收到消息
** 练习01:在原有的基础上修改程序,让客户端能够循环发送消息给服务端 直到 输入 ## 则两侧都结束
比较直接的思路:先把收发双方的收发函数放入循环,在客户端发送之后判断发送的消息是否为"##“,是则退出循环,在服务端判断接收的内容是否为字节串形式的”##",是则退出循环
以上思路其实不符合实际,服务端是长期运行的,并不会轻易退出,所以通常服务端就是“死循环”,而客户端也在满足特定条件时直接触发退出动作,无需通知服务端
拓展知识:如今的部分大型游戏公司如何实现“不停服更新”?
——公司需要有两批服务器,一主一次,相互协调,保证任何时候都有至少一台服务器运行
服务端客户端收发消息流程
** 练习02:
编写一个udp服务端和客户端程序完成下面功能
从客户端输入单词,发送给服务端,然后从服务端得到单词解释打印出来 输入##退出, 服务端可以利用 dict数据库进行单词查找 (Hard版: 使用面向对象编程完成)
1.2.4 UDP套接字特点
-
可能会出现数据丢失的情况
UDP的收发是完全对应的,也就是说一次发送只对应一次接收,如果单次发送的数据字节数超过了设置的上限,就会丢包,这就要求我们合理估算数据的大小
-
传输过程简单,实现容易
-
数据以数据包形式表达传输
-
数据传输效率较高