1.引言
单纯说到网络编程,你会想到什么呢?是我们日常业务应用web开发吗?算。但严格意义上不是,web开发相对应于http协议,属于应用层的开发。我们说到网络编程的时候,通常意义是指针对于网络层和传输层协议的应用开发,即socket编程。
2.网络模型与协议
2.1.OSI七层模型
OSI(Open System Interconnect)开放式系统互联,是国际标准化组织ISO研究的网络互联模型,从整个框架上来看,有七层:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。
七层可以再从两个维度来看,分别是:
- 媒介层:第一层,到第三层。即(物理层,数据链路层,网络层)。与硬件相关,比如路由,交换,电缆规格
- 主机层:第四层,到第七层。即(传输层,会话层,表示层,应用层)。它们表达实现网络服务的相关软件
详细信息,我们看一个图:

按理说,OSI定义了标准模型,但是很遗憾,它却没有成为工业上的事实标准,理由如下:
- OSI专家缺乏实际经验,缺少商业驱动,它是理论的产物
- OSI协议过于复杂,运行效率低下
- 标准制定周期长,市场被其它标准优先占据,失去了市场机会
- 层次划分不合理,部分功能在多个层中出现
综合以上因素,你应该想到了工业上的事实标准是谁!
2.2.TCP四层模型
TCP/IP四层模型,它综合OSI七层模型做了精简合并优化。
- 应用层:最高层,通过应用进程间通信来实现网络应用。主要负责把应用程序中的用户数据传达到另外一台主机、或者同一主机中的其它应用程序,常用应用层协议有SMTP、POP3、SSH、FTP、HTTP等
- 传输层: 负责在两个主机进程间的通信提供通用数据传输服务,常用的传输层协议有TCP、UDP
- 网络层:负责为分组交换网上的主机提供通信服务,常用的网络层协议有IP、ICMP
- 链路层:数据链路层:通常包括操作系统中设备驱动程序和计算机对应的网络接口卡,常用的链路层协议有ARP、RARP
用图来表达,是这样:

2.3.分层模型工作示例
在实际的应用中,各层各司其职,我们 以FTP客户端通信流程为例,说明两台主机是如何工作在TCP/IP分层模型上的 :

3.网络编程模型
网络编程socket是操作系统提供的编程接口,抽象简化在网络编程应用中方便与底层硬件和协议交互。
3.1.基于TCP的socket编程模型

3.2.基于UDP的socket编程模型

4.实践案例
以基于TCP网络通信应用为示例。
4.1.服务端
python
import socket
import threading
# 1.创建socket服务端对象
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.绑定服务端地址和端口
server.bind(('0.0.0.0',5000))
# 3.监听
server.listen()
print("服务端启动成功,监听端口:5000")
# 4.定义socket客户端连接处理函数,支持多客户端连接
def handle_client(sock,address):
while True:
# recv方法会阻塞
data = sock.recv(1024)
message = data.decode("utf8")
print("【来自客户端%s的消息】:%s" % (address, message))
if message=="bye":
sock.send("bye".encode("utf8"))
break
# 从console输入信息,发送给客户端
input_data = input("请输入要发送给客户端的信息:")
sock.send(input_data.encode("utf8"))
# 5.循环接收客户端连接
while True:
# 阻塞等待连接
sock,address = server.accept()
# 每个客户端连接,都创建一个线程,由线程去处理
threading.Thread(target=handle_client,args=(sock,address)).start()
启动服务端:

4.2.客户端
python
import socket
# 1.创建socket客户端对象
client = socket.socket()
# 2.连接服务端
client.connect(('127.0.0.1',5000))
print("客户端连接成功!")
# 3.循环处理消息发送接收
while True:
# 从console输入信息,发送给服务端
input_data = input("请输入要发送给服务端的信息:")
client.send(input_data.encode("utf8"))
# recv方法会阻塞
data = client.recv(1024)
message = data.decode("utf8")
print("【来自服务端的消息】:%s" % message)
if message == "bye":
print("客户端退出!")
break
# 4.关闭连接
client.close()
启动客户端,向服务端发送数据:

服务端响应:

4.3.自定义web服务器
web编程主要是http/https协议,而http协议的底层其实是TCP和UDP协议。所以我们基于网络socket接口,可以定义自己的web服务器。比如像我这样简单模拟以下:
python
import socket
import threading
# 1.创建socket服务端对象
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.绑定服务端地址和端口
server.bind(('0.0.0.0',8080))
# 3.监听
server.listen()
print("web服务启动成功,监听端口:8080")
# 4.定义socket客户端连接处理函数,支持多客户端连接
response_template = '''HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<html>
<head>
<title>web server</title>
</head>
<body>
你好!通过socket实现http web服务。
</body>
</html>
'''
def handle_client(sock,address):
while True:
# recv方法会阻塞
data = sock.recv(1024)
message = data.decode("utf8")
request_line = message.splitlines()
if request_line:
request_head = request_line[0].split();
method = request_head[0]
path = request_head[1]
print("请求方法:%s, 请求路径:%s" % (method, path))
sock.send(response_template.encode("utf8"))
# 释放资源
sock.close()
break
# 5.循环接收客户端连接
while True:
# 阻塞等待连接
sock,address = server.accept()
# 每个客户端连接,都创建一个线程,由线程去处理
threading.Thread(target=handle_client,args=(sock,address)).start()
启动web应用:

浏览器访问:http://127.0.0.1:8080

server控制台:

你看这样我们就等于自己定义了一个web服务器,本质上我们只要遵循http协议标准,通过socket接口很容易开发web服务器应用。核心代码片段:
