Python线程项目:TCP服务端提供多客户端下载功能
在上一篇博客中,我提出了3个问题,并对这些问题给出相应的答案。我们理解了线程,了解了UDP协议,结合线程和UDP协议的特点和编程语言当中提供的函数,完成了UDP客户端即时通讯的功能。在本篇博客中,我们依然运用线程的知识,在另一种网络协议TCP中,完成TCP服务端提供多客户端下载功能。首先我们需要了解TCP网络协议的特点以及其在Python当中的体现。
TCP协议的主要特点
- TCP是面向连接的运输层协议;
- 每一条TCP连接只能有两个端点(即两个套接字),只能是点对点的;
- TCP提供可靠的传输服务。传送的数据无差错、不丢失、不重复、按序到达;
- TCP提供全双工通信。允许通信双方的应用进程在任何时候都可以发送数据,因为两端都设有发送缓存和接受缓存;
- 面向字节流。虽然应用程序与TCP交互是一次一个大小不等的数据块,但TCP把这些数据看成一连串无结构的字节流,它不保证接收方收到的数据块和发送方发送的数据块具有对应大小关系,例如,发送方应用程序交给发送方的TCP10个数据块,但就受访的TCP可能只用了4个数据块久保收到的字节流交付给上层的应用程序,但字节流完全一样。
TCP协议在Python中的使用
import socket,threading
#客户端的代码
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#连接服务器端,传入服务器ip地址和端口号
client.connect(('127.0.0.1',5566))
#向服务器端发送请求信息
while True:
data = input()
client.send(data.encode('utf-8'))
info = client.recv(1024*10)
print('服务器传回的数据:',info.decode('utf-8'))
print('-----------------------------------------------------')
#服务器端的代码
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 设置服务器端的端口号
server.bind(('127.0.0.1',5566))
server.listen(5)
def run(clientsocket):
data = clientsocket.recv(1024*10)
print('客户端传来:',data.decode('utf-8'))
#发送数据给客户端
clientsocket.send('very very happy!!'.encode('utf-8'))
while True:
client_socket,client_addr = server.accept()
t = threading.Thread(target=run,args=(client_socket,))
t.start()
观察上面代码,可以发现客户端无限次数向服务端传送数据,然后服务器接收到客户端传来的数据,向客户端发送“very very happy!!”的内容。和UDP协议相同,socket模块也提供了TCP网络协议的基本操作。选择在socket方法中填写类型,绑定或者链接端口信息,然后就可以发送和接收数据了!接下来,完成本篇博客的功能需求。
需求:
客户端下载服务器端的图片
服务器端: 面对多个客户端的下载,一般服务器会把传送图片的过程写到线程当中。并发的给客户端传递信息 ---》多线程:读取图片,然后把内容send出去
客户端 :连接服务器connect ,发送请求给服务器,接收服务器相应数据 字节数组,字节写入到文件 ----》单线程
介绍了TCP在python中的运用,分析了需求之后,根据上述分析,开始编写实现功能的代码。
因为是多个客户端访问服务器,下载文件,所以服务器内部要开启多线程,便于接受客户端信息后,向客户端发送文件的操作,首先编写线程的逻辑代码。
import threading,os
class DownloadTread(threading.Thread):
def __init__(self,client,path):
"""
:param client: 客户端套接字
:param path: 图片路径
"""
threading.Thread.__init__(self)
self.client = client
self.path = path
#读文件的方法
def dealFile(self,abspath):
try:
#以二进制的形式对于图片进行读取
file = open(abspath,'rb')
mes = file.read()
except:
print('没有这个图片')
else:
file.close()
return mes
def run(self):
# 接受客户端信息
cinfo = self.client.recv(1024)
# 获取客户端要下载的图片名称
name = cinfo.decode('utf-8')
if name=='dog':#如果客户端输入名称是dog,则传送给客户端dog图片
abspath = os.path.join(self.path,'dog.png')
mess = self.dealFile(abspath)
if mess!=None:
self.client.send(mess)
self.client.close()
elif name == 'cat':#如果客户端输入名称是cat,则传送给客户端cat图片
abspath = os.path.join(self.path,'cat.png')
mess = self.dealFile(abspath)
if mess != None:
self.client.send(mess)
self.client.close()
然后在服务器端开启这个线程对象。创建一个py文件,编写服务器代码。
import socket
from server_thread import DownloadTread
if __name__ == '__main__':
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8888))
server.listen(5)
path = 'D:/image'
while True:
clientSocket,clientAddr = server.accept()
dt = DownloadTread(clientSocket,path)
dt.start()
因为可以提供多客户端同时下载的操作,这里我只写一个客户端代码,其他与之类似。
import socket
if __name__ =='__main__':
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8888))
client.send('dog'.encode('utf-8'))
info = client.recv(1024*20)
if info!=None:
#写入文件的操作
with open('dog.png','wb') as f:
f.write(info)
client.close()
接下来就可以运行服务端代码,开启服务器,等待客户端运行下载图片了~~大家可以自己编写一下,然后试试!!
感谢您的阅读!