网络编程
网络
将具有独立功能的多台计算机通过通信线路和通信设备连接起来,在网络管理软件及网络通信协议下,实现资源共享和信息传递的虚拟平台。

要使用编程语言实现多台计算机的网络通信,需要具备网络编程三个要素:

查看IP地址与检查网络
- 查看IP地址与检查网络
- Linux和mac OS 使用 ifconfig 这个命令
- Windows 使用 ipconfig 这个命令
- 检查网络是否正常使用 ping命令
- ping www.baidu.com 检查是否能上公网
- ping 当前局域网的ip地址 检查是否在同一个局域网内
- ping127.0.0.1 检查本地网卡是否正常
端口号的分类

'

协议
通信过程中, 数据不能随便发送,在发送之前还需要规则,以保证程序之间按照指定的规则来进行数据的通信,而这个规则就是TCP协议。
- TCP的英文全拼(Transmissign Control Protoco)简称传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- TCP 通信步骤: 1创建连接 2传输数据 3关闭连接

- TCP通信模型相当于生活中的打电话,在通信开始之前,一定要先建立好连接,才能发送数据,通信结束要关闭连接
3次握手
三次握手(Three-Way Handshake)就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立

- 第一次握手: 客户端向服务端发送请求,等待服务端确认。
- 第二次握手: 服务端收到请求后知道客户端请求建立连接,回复给客户端以确认连接请求。
- 第三次握手: 客户端收到确认后,再次发送请求确认服务端,服务端收到正确请求后,如果正确则连接建立成功,完成三次握手,随后客户端与服务端之间可以开始传输数据了。
4次挥手
四次挥手说TCP断开链接的时候需要经过4次确认。TCP连接是双向,A连接B、B连接A都要断开

- 第一次挥手: 当主机A(可以是客户端也可以是服务端)完成数据传输后,提出停止TCP连接的请求
- 第二次挥手: 主机B收到请求后对其作出响应,确认这一方向上的TCP连接将关闭
- 第三次挥手: 主机B端再提出反方向的连接关闭请求
- 第四次挥手: 主机A对主机B的请求进行确认,双方向的关闭结束
TCP的特点
- 面向连接
通信双方必须先建立好连接才能进行数据传输,数据传输完成后,需要断开连接,以释放系统资源。
- 可靠传输
- 通过三次握手确保连接可靠性, 通过四次挥手确保数据传输完整性
- 必须要先建立连接,相对UDP效率较低
- 大多数服务器程序都是使用TCP协议开发的,比如文件下载,网页浏览等
socket套接字
socket(简称套接字)是一个进程之间的通信工具,进程之间想要进行网络通信需要基于这个socket。

- socket(套接字)能实现不同主机之间的进程间通信。Python中有专门的socket类:

- 要使用socket,则通常要使用到socket模块下的socket类创建socket对象:

-
示例代码
import socket
"""
目标: 创建了一个TCP套接字连接
1.导入socket模块
2.使用socket.socket()函数创建一个基于IPv4(AF_INET)的TCP流套接字(SOCK_STREAM)
3.最后打印出这个套接字对象的信息。
"""tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(tcp_socket)
TCP开发流程介绍

服务器开发
当有了socket对象后,常用于服务器端的函数如下:

代码示例
"""
服务端与客户端通信
开发流程:
1.创建socket对象
2.绑定ip和端口号
3.设置最大监听数
4.等待客户端连理连接
5.给客户端发送消息
6.接收客户端的消息并打印
7.释放资源
细节:
客户端和服务端使用过 字节流(bytes) 的形式交互数据
"""
import socket
# 创建socket对象, socket.AF_INET表示ipv4, socket.SOCK_STREAM表示字节流(TCP)
server_socker = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socker.bind(("127.0.0.1", 8080))
server_socker.listen(5)
# 等待客户端建立链接, accept_socket表示链接对象(用于后续通信), client_info表示客户端信息
accept_socket, client_info = server_socker.accept()
# 给客户端发送消息
accept_socket.send(b"hello world")
# 接收客户端的消息并打印
data = accept_socket.recv(1024).decode("utf-8")
print(f'服务端收到信息: {data}, 客户端是: {client_info}')
# 释放资源
accept_socket.close()
# 服务器端一般不关闭
# server_socker.close()
客户端开发
当有了socket对象后,常用于客户端的函数如下:

代码示例
"""
客户端与服务端通信
开发流程:
1.创建socket对象
2.连接服务端, 指定ip和端口
3.接收服务端的信息并打印
4.给服务端发送消息
5.释放资源
"""
import socket
# 创建客户端
client_soket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建连接
client_soket.connect(("127.0.0.1", 8080))
# 接收服务端信息并打印
data = client_soket.recv(1024).decode("utf-8")
print(f'服务端发送信息: {data}')
# 给服务端发送消息
client_soket.send("Socket挺厉害呢!".encode("utf-8"))
# 释放资源
client_soket.close()
字符串str与二进制bytes类型转换
在网络中,数据是以二进制数据类型bytes的形式进行传递的,所以在我们向网络传输数据的时候需要把数据转化成二进制,从网络中接受到的数据默认也是二进制类型的数据,想要正常使用这些数据也需要把这些数据从二进制类型数据转化为字符串str型。
- 当字符串str数据转换为二进制bytes类型时,可使用如下函数:

- 当二进制bytes数据转换为字符串str类型时,可使用如下函数:

-
示例代码
"""
演示编解码
1.编码 = 把数据转成二进制
'字符串'.encode(码表)
2.解码 = 把二进制转成数据
二进制.decode(码表)
3.只要乱码了,就是编码出现了不同
4.英文字母,数字,特殊符号无论什么码表都只占1个字节, 中文在gbk中占2个字节,在utf-8中占3个字节
5.二进制数据特殊写法, b'字母 数字 特殊符号', 该方式不支持中文
"""编码
s1 = '你好'
print(s1.encode()) #b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(s1.encode('utf-8')) #b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(s1.encode('gbk')) #b'\xc4\xe3\xba\xc3'解码
bys = b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(type(bys)) #<class 'bytes'>
print(bys.decode()) #你好
print(bys.decode('utf-8')) #你好
print(bys.decode('gbk')) #乱码
设置端口号重用
当客户端和服务端建立连接后,服务端程序退出后端口号不会立即释放,需要等待大概1-2分钟。解决办法有两种:
- 更换服务端端口号
- 设置端口号复用(推荐大家使用),也就是说让服务端程序退出后端口号立即释放。
设置端口号复用的代码如下:
- 一般都会自动重用, 某些CPU可能不重用, 出现端口占用时再设置就行

文本上传

"""
客户端上传文本文件
"""
import socket
# 创建客户端
client_soket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建连接
client_soket.connect(("127.0.0.1", 8080))
# 关联数据源文件, 读取内容, 发送给服务器
with open("data.txt", "rb") as src_f:
while True:
data = src_f.read(8192)
client_soket.send(data)
if len(data) == 0:
break
# 释放资源
client_soket.close()
"""
服务端接收文本文件
"""
import socket
# 创建socket对象, socket.AF_INET表示ipv4, socket.SOCK_STREAM表示字节流(TCP)
server_socker = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socker.bind(("127.0.0.1", 8080))
server_socker.listen(5)
# 等待客户端建立链接, accept_socket表示链接对象(用于后续通信), client_info表示客户端信息
accept_socket, client_info = server_socker.accept()
with open("my_data.txt", "wb") as dest_f:
while True:
# 接收客户端文件数据
bys = accept_socket.recv(8192)
if len(bys) == 0:
break
# 写入操作
dest_f.write(bys)
# 释放资源
accept_socket.close()
图片上传
"""
客户端上传图片文件
"""
import socket
# 创建客户端
client_soket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建连接
client_soket.connect(("127.0.0.1", 8080))
# 关联数据源文件, 读取内容, 发送给服务器
with open("字体1.jpg", "rb") as src_f:
while True:
data = src_f.read(8192)
client_soket.send(data)
if len(data) == 0:
break
# 释放资源
client_soket.close()
"""
服务端接收文本文件
"""
import socket
# 创建socket对象, socket.AF_INET表示ipv4, socket.SOCK_STREAM表示字节流(TCP)
server_socker = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socker.bind(("127.0.0.1", 8080))
server_socker.listen(5)
while True:
try:
# 等待客户端建立链接
accept_socket, client_info = server_socker.accept()
with open("001.jpg", "wb") as dest_f:
while True:
# 接收客户端文件数据
bys = accept_socket.recv(8192)
if len(bys) == 0:
break
# 写入操作
dest_f.write(bys)
# 释放资源
accept_socket.close()
except:
pass