CH12. 网络编程
网络协议概述
网络编程与通信协议
-
什么是通信协议?
-
协议即规则,就好比汽车上路要遵守交通规则一样,为了使全世界不同类型的计算机都可以连接起来,所以制定了一套全球通用的通信协议——Internet协议,任何私有网络,只要支持这个协议,就可以接入互联网。
-
-
TCP协议与UDP协议
-
TCP/IP协议
- IP协议是整个TCP/IP协议簇的核心
- IP地址就是互联网上计算机的唯一标识
- 目前的IP地址有两种表达方式,即IPv4和IPv6
- 在命令行下使用ipconfig命令行可以查看本机的ip地址(Windows)
-
TCP(Transmission Control Protocol)协议即传输控制协议,是建立在IP协议基础之上的。TCP协议负责两台计算机之间建立可靠连接,保证数据包按顺序发送到。它是一种可靠的、一对一的、面向有连接的通信协议
-
-
TCP协议的三次握手
-
-
UDP协议
- UDP协议又被称为用户数据包协议(User Datagram Protocol),它是面向无连接的协议,只要知道对方的IP地址和端口,就可以直接发送数据包,由于是面向无连接的,所以无法保证数据一定会到达接收方。
-
端口号
- 区分计算机中运行的应用程序的整数
- 端口号的取值范围是0~65535,一共65536个,其中80这个端口号分配给了HTTP服务,21这个端口号分配给了FTP协议
-
TCP协议与UDP协议的区别
TCP协议 | UDP协议 | |
---|---|---|
连接方面 | 面向连接的 | 面向无连接 |
安全方面 | 传输消息可靠、不丢失、按顺序到达 | 无法保证不丢包 |
传输效率方面 | 传输效率相对较低 | 传输效率高 |
连接对象数量方面 | 只能是点对点、一对一 | 支持一对一、一对多、多对多的交互通信 |
Socket套接字
-
Socket简介
- 所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口
-
Socket对象的常用方法
socket
模块
方法名称 | 功能描述 |
---|---|
bind(ip, port) | 绑定ip地址和端口 |
listen(N) | 开始TCP监听,N表示操作系统挂起的最大连接数量,取值范围1-5之间,一般设置为5 |
accept() | 被动接收TCP客户端连接,阻塞式 |
connect((ip,port)) | 主动初始化TCP服务器连接 |
recv(size) | 接收TCP数据,返回值为字符串类型,size表示要接收的最大数据量 |
send(str) | 发送TCP数据,返回值是要发送的字节数量 |
sendall(str) | 完整发送TCP数据,将str中的数据发送到连接的套接字,返回之前尝试发送所有数据,如果成功为None,失败抛出异常 |
recvfrom() | 接收UDP数据,返回值为一个元组(data,address),data表示接收的数据,address表示发送数据的套接字地址 |
sendto(data,(ip,port)) | 发送UDP数据,返回值是发送的字节数 |
close() | 关闭套接字 |
TCP编程
- TCP服务器端流程如下:
- 使用socket类创建一个套接字对象
- 使用bind((ip,port))方法绑定IP地址和端口号
- 使用listen()方法开始TCP监听
- 使用accept()方法等待客户端的连接
- 使用recv()/send()方法接收/发送数据
- 使用close()关闭套接字
from socket import AF_INET, SOCK_STREAM, socket
# AF_INET 用于Internet之间的进程通信
# SOCK_STREAM 表示的是用TCP协议编程
# (1)创建socket对象
server_socket = socket(AF_INET, SOCK_STREAM)
# (2)绑定IP地址和端口号
ip = '127.0.0.1' # 等同于local
port = 8888 # 端口的范围
server_socket.bind((ip, port))
# (3)使用listen()开始监听
server_socket.listen(5)
print('服务器已启动...')
# (4)等待客户端的连接
client_socket,client_addr = server_socket.accept()
# (5)接收来自客户端的数据
data = client_socket.recv(1024)
print('客户端发送过来的数据为:', data.decode('utf-8')) # 要求客户端发送过来的数据使用utf-8进行编码
# (6)关闭socket
server_socket.close()
PS D:\2_Demolight\python\study-plan\single-files> & C:/Python312/python.exe d:/2_Demolight/python/study-plan/single-files/test_tcp_server.py
服务器已启动...
客户端发送过来的数据为: Welcome to python world
- TCP客户端的流程:
- 使用socket类创建一个套接字对象
- 使用connect((host,port))设置连接的主机IP和主机设置的端口号
- 使用recv()/send()方法接收/发送数据
- 使用close()关闭套接字
import socket
# (1)创建socket对象
client_socket = socket.socket()
# (2) 连接IP地址和主机端口
ip = '127.0.0.1'
port = 8888
client_socket.connect((ip, port))
print('与服务器简历连接成功...')
# (3)发送数据
client_socket.send('Welcome to python world'.encode('utf-8'))
# (4)关闭socket
client_socket.close()
print('发送完毕')
PS D:\2_Demolight\python\study-plan\single-files> python .\test_tcp_client.py
与服务器简历连接成功...
发送完毕
-
需要先启动服务器端
-
TCP服务器端与客户端的连接过程
TCP多次通信
# test_tcp_server_multi_msg.py
import socket
# AF_INET 用于Internet之间的进程通信
# SOCK_STREAM 表示的是用TCP协议编程
# (1)创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# (2)绑定IP地址和端口号
ip = '127.0.0.1' # 等同于local
port = 8888 # 端口的范围
server_socket.bind((ip, port))
# (3)使用listen()开始监听
server_socket.listen(5)
print('服务器已启动...')
# (4)等待客户端的连接
client_socket,client_addr = server_socket.accept()
# (5)接收来自客户端的数据
msg = client_socket.recv(1024).decode('utf-8')
while msg != 'bye':
if msg!='':
print('客户端发送过来的数据为:', msg) # 要求客户端发送过来的数据使用utf-8进行编码
# 准备发送数据
data = input('请输入要发送的数据:')
# 服务器端回复客户端
client_socket.send(data.encode('utf-8')) # 往client_socket发送
if data == 'bye':
break
msg = client_socket.recv(1024).decode('utf-8')
# (6)关闭socket
client_socket.close()
server_socket.close()
PS D:\2_Demolight\python\study-plan\single-files> & C:/Python312/python.exe d:/2_Demolight/python/study-plan/single-files/test_tcp_server_multi_msg.py
服务器已启动...
客户端发送过来的数据为: hello
请输入要发送的数据:hi
# test_tcp_client_multi_msg.py
import socket
client_socket = socket.socket()
server_ip = '127.0.0.1'
server_port = 8888
client_socket.connect((server_ip, server_port))
msg = ''
while msg != 'bye':
send_data = input('请客户端输入要发送的数据:')
client_socket.send(send_data.encode('utf-8'))
if send_data == 'bye':
break
msg = client_socket.recv(1024).decode('utf-8')
print('收到服务器的相应消息:', msg)
PS D:\2_Demolight\python\study-plan\single-files> python .\test_tcp_client_multi_msg.py
请客户端输入要发送的数据:hello
收到服务器的响应消息: hi
请客户端输入要发送的数据:bye
PS D:\2_Demolight\python\study-plan\single-files>
UDP编程
一次UDP双向通信
# test_udp_sender.py
from socket import AF_INET, SOCK_DGRAM, socket
# (1)创建socket对象
send_socket = socket(AF_INET, SOCK_DGRAM)
# (2)准备发送数据
data = input('请输入要发送的数据:')
# (3)指定接收方的ip地址和端口
ip_port = ('127.0.0.1', 8888)
# (4)发送数据
send_socket.sendto(data.encode('utf-8'), ip_port)
# 接收来自接收方的回复数据
recv_data, addr = send_socket.recvfrom(1024)
print('接收到的数据为:', recv_data.decode('utf-8'))
# (5)关闭socket
send_socket.close()
PS D:\2_Demolight\python\study-plan\single-files> & C:/Python312/python.exe d:/2_Demolight/python/study-plan/single-files/test_udp_sender.py
请输入要发送的数据:hello
接收到的数据为: hi
# test_udp_reciver.py
from socket import AF_INET, SOCK_DGRAM, socket
recv_socket = socket(AF_INET, SOCK_DGRAM)
# 绑定ip地址和端口
recv_socket.bind(('127.0.0.1', 8888))
recv_data, addr = recv_socket.recvfrom(1024)
print('接收到数据:', recv_data.decode('utf-8'))
data = input('请输入要回复的数据:')
recv_socket.sendto(data.encode('utf-8'), addr)
recv_socket.close()
PS D:\2_Demolight\python\study-plan\single-files> python .\test_udp_reciver.py
接收到数据: hello
请输入要回复的数据:hi
- reviver端程序先启动
模拟客服咨询小程序
# test_udp_service_miniapp.py
from socket import AF_INET, SOCK_DGRAM, socket
recv_socket = socket(AF_INET, SOCK_DGRAM)
recv_socket.bind(('127.0.0.1', 8888))
while True:
recv_msg, addr = recv_socket.recvfrom(1024)
print('客户说:',recv_msg.decode('utf-8'))
if recv_msg.decode('utf-8') == 'bye':
break
data = input('客服回复:')
recv_socket.sendto(data.encode('utf-8'), addr)
recv_socket.close()
PS D:\2_Demolight\python\study-plan\single-files> & C:/Python312/python.exe d:/2_Demolight/python/study-plan/single-files/test_udp_service_miniapp.py
客户说: 你好
客服回复:hello
客户说: 这个怎么卖
客服回复:这个不卖
客户说: bye
from socket import AF_INET, SOCK_DGRAM, socket
client_socket = socket(AF_INET, SOCK_DGRAM)
while True:
msg = input('客户说:')
client_socket.sendto(msg.encode('utf-8'), ('127.0.0.1', 8888))
if msg == 'bye':
break
recv_data, addr = client_socket.recvfrom(1024)
print('客服回复:', recv_data.decode('utf-8'))
client_socket.close()
PS D:\2_Demolight\python\study-plan\single-files> python .\test_udp_client_miniapp.py
客户说:你好
客服回复: hello
客户说:这个怎么卖
客服回复: 这个不卖
客户说:bye
PS D:\2_Demolight\python\study-plan\single-files>