python高级之网络概述2
2.11综合案例:udp聊天器
import socket
def send_data1(udp_socket):
# 准备发送数据
send_data = input("请输入您要发送的数据:")
# 对发送的数据进行二进制编码
send_content = send_data.encode("utf-8")
ip_address = input("请输入对方的ip地址:")
port = int(input("请输入对方的端口号:"))
# 发送数据
udp_socket.sendto(send_content, (ip_address, port))
def receive_data1(udp_socket):
# 接收数据
recv_data, ip_port = udp_socket.recvfrom(1024)
# 对接收的数据进行解码
recv_content = recv_data.decode("utf-8")
print(recv_content, ip_port)
if __name__ == '__main__':
# 创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(("", 8080))
while True:
num = int(input("请输入功能对应的数字:1.发送数据 2.接收数据 3.退出"))
if num == 1:
send_data1(udp_socket)
elif num == 2:
receive_data1(udp_socket)
elif num == 3:
break
# 关闭套接字
udp_socket.close()
2.12tcp网络程序——tcp客户端
import socket
if __name__ == '__main__':
# 创建tcp客户端socket
# 1. AF_INET:表示ipv4的地址类型
# 2. SOCK_STREAM: 表示使用tcp的传输协议
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 和服务端socket建立连接
tcp_client_socket.connect(("192.168.131.106", 8989))
# 准备发送的数据
send_content = "哈哈,我使用tcp发送数据啦~"
# 对数据进行gbk的编码
send_data = send_content.encode("gbk")
# 发送数据
tcp_client_socket.send(send_data)
# 接收数据, 1024:表示每次接收最大的字节数
recv_data = tcp_client_socket.recv(1024)
# 解码数据
recv_content = recv_data.decode("gbk")
print(recv_content)
# 关闭socket
tcp_client_socket.close()
2.13tcp网络程序——tcp服务端
import socket
if __name__ == '__main__':
# 创建tcp服务端socket
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 扩展-立即释放端口号,重用端口
# SOL_SOCKET: 表示当前socket
# SO_REUSEADDR: 是否立即是否端口选项
# True:表示立即是否端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口号
tcp_server_socket.bind(("", 7878))
# 设置监听,把主动套接字变成被动套接字, 被动套接字:以后只能接收客户端连接请求,不能收发消息,收发消息使用返回的新套接字
# 128:表示等待的最大连接数
tcp_server_socket.listen(128)
# 等待接收客户端连接请求, 返回一个新的套接字说明建立连接成功,以后和客户端通信使用service_client_socket
# accept会一直等待客户端建立连接,只有连接建立成功才会继续往下执行代码否则一直等待
service_client_socket, ip_port = tcp_server_socket.accept()
print(ip_port)
# 接收客户端的消息
recv_data = service_client_socket.recv(1024)
print(recv_data, len(recv_data))
# 解码数据
recv_content = recv_data.decode("gbk")
print(recv_content)
# 发送数据
service_client_socket.send("ok,问题正在处理中...".encode("gbk"))
# 关闭服务于客户端的socket
service_client_socket.close()
# 关闭服务端的socket
tcp_server_socket.close()
2.14案例:文件下载器
2.14.1tcp文件下载器客户端
import socket
if __name__ == '__main__':
# 创建tcp客户端socket
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 和服务端socket建立连接
tcp_client_socket.connect(("192.168.131.106", 7878))
# 接收用户输入的文件名
file_name = input("请输入您要下载的文件对应的名字:")
# 对字符串进行编码
file_name_data = file_name.encode("gbk")
# 发送下载文件的请求信息
tcp_client_socket.send(file_name_data)
# 定义二进制空的数据
result_file_data = b""
# 循环接收数据
while True:
# 获取服务端发送的文件二进制数据
file_data = tcp_client_socket.recv(1024)
if file_data:
# 拼接每次读取的数据
result_file_data += file_data
else:
break
# 判断文件是否有数据
if result_file_data:
# 写入到指定文件里面, with open 文件操作完成以后关闭文件是系统自己操作的
with open("/home/python/Desktop/" + file_name, "wb") as file:
file.write(result_file_data)
else:
print("文件不存在")
# 关闭socket
tcp_client_socket.close()
2.14.2tcp文件下载器服务端
import socket
import os
if __name__ == '__main__':
# 创建tcp服务端socket
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定端口号
tcp_server_socket.bind(("", 7878))
# 设置监听,把主动套接字改成被动套接字,被动套接字只能接收客户端连接请求,不能收发消息,收发消息使用新的套接字
tcp_server_socket.listen(128)
# 注意点:目前服务端是单任务的一个人下载完成以后另外一个人才能再下载
# 循环接收客户端连接请求
while True:
# 等待接收客户端的连接请求
tcp_service_socket, ip_port = tcp_server_socket.accept()
print(ip_port)
# 接收客户端的请求信息,其实文件名
file_name_data = tcp_service_socket.recv(1024)
# 对二进制数据进行解码获取文件名字符串
file_name = file_name_data.decode("gbk")
# "桌面路径/" + file_name 判断指定路径是否有对应的文件
# file_name在当前工程判断该文件是否存在
if os.path.exists(file_name):
# 打开指定文件把数据发送给客户端
with open(file_name, "rb") as file:
while True:
# 读取文件中的数据
file_data = file.read(1024)
# 判断数据是否为空
if file_data:
# 发送数据给客户端
tcp_service_socket.send(file_data)
else:
break
print(file_name, ip_port)
# 和客户端终止服务
tcp_service_socket.close()
# 关闭服务端套接字,以后不再接收客户端的连接请求
tcp_server_socket.close()
2.15tcp的三次握手和四次挥手
2.15.1tcp的三次握手
标志位:
SYN:表示连接请求
ACK:表示确认
FIN:表示关闭连接
序号:
seq:表示报文序号
ack:表示确认序号
![img](file:///C:/%E8%BF%85%E9%9B%B7%E4%B8%8B%E8%BD%BD/Learn/python%E9%AB%98%E7%BA%A7%E4%B8%8A%E8%AF%BE%E8%AF%BE%E4%BB%B6/day04/imgs/tcp%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B.png)
图解流程如下:
- 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
- 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack (number )=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
- 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
2.15.2tcp的四次挥手
![img](file:///C:/%E8%BF%85%E9%9B%B7%E4%B8%8B%E8%BD%BD/Learn/python%E9%AB%98%E7%BA%A7%E4%B8%8A%E8%AF%BE%E8%AF%BE%E4%BB%B6/day04/imgs/tcp%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B.png)
图解流程如下:
- 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送。
- 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1。
- 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送。
- 第四次挥手:Client收到FIN后,接着发送一个ACK给Server,确认序号为收到序号+1。