愚公移山日记·22
学习进度
今天的主要学习内容是TCP通信。
TCP是面向连接,可靠的基于字节流的传输控制协议,TCP有一下两个的特点:一是面向连接,二是可靠传送。
可靠传输的原因有一下几点的原因:
- 应答机制
- 超时重传
- 错误校验
- 流量控制和阻塞管理
TCP和UDP的区别主要可以分为一下几点:
- 面向连接(确认有创建第三方交流,连接已创建才传输)
- 序数据传输
- 重发丢失的数据包
- 舍弃重复的数据包
- 无差别的数据传送
- 阻塞/流量控制
对于TCP的建立一般按照一下几点步骤进行,
在客户端:socket对象—>connect —>send(recv)—>close;
服务器端:socket对象—>bind—>listen—>accept—>recv(send)—>close。
服务端实现的具体步骤: - 导入模块,
- 创建套接字,
- 绑定端口,
- 开启监听(把套接字由主动设置为被动),
listen(128) 最大连接数目,等待客户端连接
拆包, 使用新的套接字接受客户端发送的信息
new_client_socket.recv(1024) - 关闭新的套接字
new_client_socket.close() - 关闭服务器的套接字
tcp_server_socket.closer()
服务器不再接受新的客户,老客户端可以继续服务
实现TCP通信的的代码
TCP客户端
"""
导入模块
创建套接字 TCP
建立连接 connect()
发送数据
关闭套接字
"""
#导入模块
import socket
#创建套接字 TCP
#socket.SOCK_STREAM TCP 传输方式
#socket.SOCK_DGRAM UPD 传输方式
tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立连接 connect()
#tcp_client_socket.connect(adress)
#adress 是一个元组,第一个表示的是字符串的IP地址,第二个表示的端口号
tcp_client_socket.connect(('',8080))
#发送数据
tcp_client_socket.send('字符串'.encode())
#接受信息
recv_data = tcp_client_socket.recv(1024)
#recv_data 保存的是客户端回复的信息的二进制
#解码
recv_text = recv_data.decode('gbk')
print('收到数据:',recv_text)
#关闭套接字
tcp_client_socket.close()
TCP通信的服务端
#导入模块
import socket
#创建套接字
tcp_server_socke = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定端口和IP地址
tcp_server_socke.bind(('',8999))
#开启监听(设置套接字为被动模式)
#listen()作用设置 tcp_server_socke套接字为被动监听模式,不可以主动发送数据
#128 允许接受的最大的连接数目 ,windows 中是数据有效,而Linux中的数据无效
tcp_server_socke.listen(128)
#等待客户端连接
#accept() 开始接受客户端连接,程序会默认进入阻塞状态(等待客户端连接),如果客户端连接后程序自动接触阻塞
#recv_data 数据包含两不部分
#返回了一个新的套接字对象 socket
#客户端的IP地址和端口号 元组类型
while True :
#这个循环是未让多个客户端同时进行,但是由于需要多线程。
new_client_socket,client_ip_port = tcp_server_socke.accept()
print('新客户端来啦:%s' %str(client_ip_port))
#收发数据
while True:
#recv() 会让程序再次阻塞,收到信息之后再接着阻塞
recv_data = new_client_socket.recv(1024)
# 当接受到的数据为空的时候,表示客户端已经断开连接,服务端也要断开连接。
if recv_data:
recv_text = recv_data.decode('bgk')
print('接收到[%s]的信息:%s' %(str(client_ip_port),recv_text))
else:
print('客户端已经断开连接')
#new_client_socket() 表示不能再和当前的客户端通信
new_client_socket.close()
#关闭连接
#tcp_server_socke.close()表示程序不再接受新的客户端连接,已经连接的可以继续服务
tcp_server_socke.close()
在后面还学习到了TCP通信的文件下载器
客户端
'''
导入模块
创建套接字
建立连接
接受用户输入的文件名
发送文件名到服务器
创建文件,并且准备保存
接受服务端发送到数据,保存到本地(循环)
关闭套接字
'''
#导入模块
import socket
#创建套接字
tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立连接
tcp_client_socket.connect(('IP地址',8080))
#接受用户输入的文件名
file_name = input('请输入要下载的文件名:\n')
#发送文件名到服务器
tcp_client_socket.send(file_name.encode())
#创建文件,并且准备保存
with open('下载的文件路径' + file_name,'wb') as file:
while True:
file_data = tcp_client_socket.recv(1024)
if file_data:
file.write(file_data)
else:
break
#关闭套接字
tcp_client_socket.close()
服务端
'''
导入模块
创建套接字
绑定端口
设置监听,设置套接字由主动为被动
接受客户端连接
接受客户端发送的文件名称
根据文件名读取文件的内容
把读取的内容发送给客户端(循环进行)
关闭当前的客户端的连接
关闭服务器
'''
#导入模块
import socket
#创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#设置套接字可以重用
#tcp_server_socket.setsockopt(当前套接字,属性名,属性值)
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
#绑定端口
tcp_server_socket.bind(('IP地址',8080))
#设置监听,设置套接字由主动为被动
tcp_server_socket.listen(128)
#接受客户端连接
new_server_socket,ip_port = tcp_server_socket.accept()
print('欢迎新的客户端:',ip_port)
#接受客户端发送的文件名称
recv_data = new_server_socket.recv(1024)
file_name = recv_data.decode()
print(file_name)
#根据文件名读取文件的内容
with open(file_name,'rb') as file:
#把读取的内容发生过客户端(循环)
while True:
file_data = file.read(1024)
#判断是否读取了文件的末尾
if file_data:
#发送文件
new_server_socket.send(file_data)
else:
break
# 关闭和当前的客户端的连接
new_server_socket.close()
#关闭服务器
tcp_server_socket.close()
今天的分享就到这里啦