TCP实例
文件的上传,下载,查看
服务端代码
from socket import *
import os
import pickle
# 查看文件目录
def show_list(new_socket):
data = os.listdir()
data = pickle.dumps(data)
new_socket.send(data)
new_socket.close()
# 下载文件
def download(new_socket, data):
data = data.decode("utf-8")
print("下载")
if str(data[2:]) in os.listdir():
fr = open(data[2:], "rb")
content = fr.read(1024)
while content:
new_socket.send(content)
content = fr.read(1024)
new_socket.close()
else:
new_socket.send("".encode('utf-8'))
print('没有该文件')
new_socket.close()
# 上传文件
def upload(new_socket, data):
file_name = data[2:].decode("utf-8")
fw = open(file_name, "wb")
content = new_socket.recv(1024)
con = content.split("@".encode('utf-8'))[1]
while con:
fw.write(con)
con = new_socket.recv(1024)
print("上传成功")
new_socket.close()
def main():
# 创建一个对象
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
# 绑定端口ip
tcp_server.bind(("", 2121))
# 监听
tcp_server.listen(5)
while True:
# 等待连接
new_socket, client_info = tcp_server.accept()
# 接收消息
data = new_socket.recv(1024)
# 查看获取的第一位是什么
if data[0:1] == b"L":
show_list(new_socket)
elif data[0:1] == b"G":
download(new_socket, data)
elif data[0:1] == b"U":
upload(new_socket, data)
if __name__ == '__main__':
main()
客户端
from socket import *
import pickle
# 查看文件列表
def show_list():
print("查看目录")
# 创建对象
tcp_client = socket(AF_INET, SOCK_STREAM)
# 创建连接
tcp_client.connect(("47.96.154.250", 2121))
# 发送消息
tcp_client.send("L".encode('utf-8'))
# 接收消息
data = tcp_client.recv(1024)
data = pickle.loads(data)
print(f"{data}")
tcp_client.close()
# 下载文件
def download(send_data):
# print("下载文件")
# 创建对象
tcp_client = socket(AF_INET, SOCK_STREAM)
# 创建连接
tcp_client.connect(("47.96.154.250", 2121))
# 发送消息
tcp_client.send(send_data.encode('utf-8'))
# 接收消息
data = tcp_client.recv(1024)
if data:
fw = open(send_data[2:], "wb")
while data:
fw.write(bytes(data))
data = tcp_client.recv(1024)
print("下载完毕")
tcp_client.close()
else:
print("该文件不存在,请检查文件名是否正确")
# 上传文件
def upload(send_data):
# print("上传文件")
# 创建对象
tcp_client = socket(AF_INET, SOCK_STREAM)
# 创建连接
tcp_client.connect(("47.96.154.250", 2121))
# 发送消息
tcp_client.send(send_data.encode('utf-8'))
# 获取文件名
file_name = send_data[2:]
# 使用@ 将文件名和文件内容分隔
tcp_client.send((file_name + "@").encode('utf-8'))
fr = open(file_name, "rb")
content = fr.read(1024)
while content:
tcp_client.send(content)
content = fr.read(1024)
print("上传完毕")
tcp_client.close()
def main():
send_data = input("请输入:")
while True:
if send_data[0].upper() == 'L':
show_list()
elif send_data[0].upper() == 'G':
download(send_data)
elif send_data[0].upper() == 'U':
upload(send_data)
send_data = input("请输入:")
if __name__ == '__main__':
main()
序列化和反序列化
import pickle
# 将指定的Python对象通过pickle序列化作为bytes对象返回,而不是将其写入文件
dumps(obj)
# 将通过pickle序列化后得到的字节对象进行反序列化,转换为Python对象并返回
loads(bytes_object)
# 将指定的Python对象通过pickle序列化后写入打开的文件对象中,等价于`Pickler(file, protocol).dump(obj)`
dump(obj)
# 从打开的文件对象中读取pickled对象表现形式并返回通过pickle反序列化后得到的Python对象
load(file)
TCP三次握手和四次分手
TCP为什么要三次握手
- 第一次握手 客户端向服务端发送一个请求包 当服务端收到这个请求包的时间可以确定服务端的收信功能 和客户端的发信功能
- 第二次握手 服务端向客户端发送一个确认包,并同时发送一个请求包, 客户端可以确认 自己可以收发信,服务端也可以收发信
- 第三次握手 客户端向服务端发送一个确认包 服务端可以确认 自己的发信功能和客户端的收信功能,结合第一次握手的信息已经确认双方收发信功能没有问题
那分手为什么需要四次
- 客户端发送一个分手包
- 服务端收到后立马确认
- 把手头剩余的事情做完后再次发送分手包给客户端
- 客户端收到后再次发送确认包等待2MSL时间后退出,服务端收到确认包后结束连接,如果在没有收到会再次发送分手包
什么是2MSL
MSL是客户端到服务端一次通信的最长时间,如果在这个时间内没有送达,认为丢包了
一来一回最长时间就是2MSL,所以任何一方在发出信息后,如果2MSL内没有收到回复,就认为丢包
通常在四次握手最后一次,客户端发出最后确认分手包后,服务端在收到这个包后会断开连接,无法再发送消息
所以客户端只有等待这么长时间,如果在这个时间段内没有再次收到新的分手包,就认为服务端已经下线,我也是可以离开