使用网络TCP搭建一个简单文件下载器
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
目录
一丶项目介绍
1.叙述
生活中大家都使用过迅雷吧,用户在客户端上使用迅雷从服务器上download一个文件到客户端,今天博主就是使用TCP网络搭建一个客户端client连接服务器server,从服务器server上下载所想要下载的文件到客户端client上
2.项目环境
操作系统:Windows7
IDE:PyCharm2017
编程语言:python3.x
测试工具:网络调试工具3.x
二丶服务器Server
1.在PyCharm中创建file_download_tcpServer.py和file_download_tcpClient.py文件用于实现tcp服务器客户端
2.首先在file_download_tcpServer.py中进行代码逻辑编写
- step1 创建tcp socket套接字
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
- step2 绑定本地IP和端口
tcp_server_socket.bind(('', 8888))
- step3 使用listen将主动套接字变为被动套接字
tcp_server_socket.listen(128)
- step4 等待客户端的链接,即为这个客户端发送文件,因为不止一个客户连接,此时需要将(step4~7)代码写在while True里面
client_socket, clientAddr = tcp_server_socket.accept()
- step5 显示连接的客户端用户信息
print("用户%s 已连接"% str(clientAddr))
- step6 接收客户端发送过来的数据获取客户要下载的文件,并打印显示
recv_data = client_socket.recv(1024) # 接收1024个字节
file_name = recv_data.decode("utf-8")
print("对方请求下载的文件名为:%s" % file_name)
- step7 根据客户请求下载的文件名,获取该文件内容,并发送给客户端
try:
with open(filename, "rb") as f:
file_content = f.read()
except Exception as e:
print("获取文件内容出错:", e)
if file_content:
client_socket.send(file_content)
# 关闭该套接字
client_socket.close()
- step8 关闭服务器监听套接字
tcp_server_socket.close()
3.封装(解耦)代码,博主之所以这样做,是为了让大家了解一个正确开发过程,提高代码复用性
从上面代码可以看出耦合性比较严重,看着杂乱无章比较费劲,所以需要对代码进行解耦操作,降低代码耦合性,获取客户端下载文件内容可以封装到一个方法里(get_file_content),而tcp 服务器创建套接字以及关闭都可以封装到main方法里面,如下所示
def get_file_content(filename):
"""获取文件内容"""
try:
with open(filename, "rb") as f:
content = f.read()
return content
except Exception as e:
print("获取文件内容出错:", e)
def main():
# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 绑定本地信息
tcp_server_socket.bind(('', 8888))
# 使用listen将主动套接字变为被动套接字
tcp_server_socket.listen(128)
while True:
# 等待客户端的链接,即为这个客户端发送文件
client_socket, clientAddr = tcp_server_socket.accept()
print("用户%s 已连接"% str(clientAddr))
# 接收客户端发送过来的数据获取客户要下载的文件名
recv_data = client_socket.recv(1024) # 接收1024个字节
file_name = recv_data.decode("utf-8")
print("对方请求下载的文件名为:%s" % file_name)
file_content = get_file_content(file_name)
# 发送文件的数据给客户端,获取文件内容使用rb二进制,所以这里不需要进行encode编码操作
if file_content:
client_socket.send(file_content)
# 关闭客户端套接字
client_socket.close()
# 关闭服务器监听套接字
tcp_server_socket.close()
if __name__ == "__main__":
main()
4. 指定服务器运行方式为python3 xxx.py 8888,将服务器绑定端口号传入到代码中
- step1 指定TCP服务器启动为终端命令python3 xxx.py 8888方式,这个比较新颖,这里博主给大家详细进行演示,这里博主在项目目录下创建demo.py文件用于演示,在demo.py中进行如下编写
import sys
print(len(sys.argv))
- step2 在pycharm中直接运行run demo.py结果如下

- step3 在pycharm Terminal终端执行python3 demo.py 8888 ,打印出sys.argv的长度为2,结果为列表所以打印的第一个元素值为文件名第二元素的值为传入的端口号,所以说如果sys.argv的长度为1代表直接运行,为2时表示是以python3 xxx.py 8888方式运行,由此可以进行逻辑判断

- step4 在main主函数第一行加入以下代码,并将bing方法中的端口参数修改为port
def main():
import sys
if len(sys.argv) != 2:
print("请按照如下方式运行:python3 xxx.py 8888")
return
else:
# 运行方式为python3 xxx.py 8888
port = int(sys.argv[1]) # 8888
三丶测试TCP server服务器
1.在Terminal终端执行python3 file_download_tcpServer.py 没有传入端口号,出现定义的提示

2.在Terminal终端执行python3 file_download_tcpServer.py 8888即成功运行tcp 服务器并绑定8888端口,终端光标开始闪烁等待客户端的连接

3.打开网络调试助手,选择TCP client客户端,IP地址为本机IP 端口为服务器绑定端口号8888,

4.点击连接成功后,回到pycharm Terminal终端,此时终端显示用户XXXX已连接

5.在网络调试助手中发送demo.py文件名(client发送下载文件名必须存在于服务器端),此时服务器获取客户端发送的下载文件名,获取该文件的内容发送给客户端,代表服务器代码逻辑编写正确
- step1 服务端显示如下

- step2 客户端显示如下

四丶客户端Client
1.在file_download_tcpClient.py中进行代码逻辑编写,相对服务器来说客户端的代码实现就比较简单,首先定义main主函数用于客户端创建套接字连接目标服务器
- step1 创建套接字
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
- step2 连接目标服务器
tcp_client_socket.connect((input("请输入服务器ip:"), int(input("请输入服务器port:"))))
- step3 输入要下载的文件名,并向服务器发送
file_name = input("请输入要下载的文件名:")
tcp_client_socket.send(file_name.encode("utf-8"))
- step4 接收服务器发送过来的数据,接收1024个字节(1K)
recv_data = tcp_client_socket.recv(1024)
- step5 接收数据不为空时,写入到本地客户端
if recv_data:
with open("[接收]"+file_name, "wb") as f:
f.write(recv_data)
- step6 关闭客户端套接字
tcp_client_socket.close()
2.客户端完整代码
from socket import *
def main():
# 创建socket套接字
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# 连接目标服务器
tcp_client_socket.connect((input("请输入服务器ip:"), int(input("请输入服务器port:"))))
# 输入需要下载的文件名
file_name = input("请输入要下载的文件名:")
# 向服务器发送文件下载请求
tcp_client_socket.send(file_name.encode("utf-8"))
# 接收服务器发送过来的数据
recv_data = tcp_client_socket.recv(1024)
print('接收到的数据为:', recv_data.decode('utf-8'))
# 接收数据不为空时,写入到本地客户端,
if recv_data:
with open("[接收]"+file_name, "wb") as f:
f.write(recv_data)
# 关闭套接字
tcp_client_socket.close()
if __name__ == "__main__":
main()
五丶测试客户端向服务器下载文件
1.首先在Terminal终端上执行python3 file_download_tcpServer.py 8888将服务器运行在8888端口上,此时服务器正等待客户端连接

2.在pycharm上直接run运行 file_download_tcpClient.py客户端
- step1 运行后则显示输入服务器的IP,端口以及要下载的文件名,发送请求给服务器成功则服务器会将该文件的内容发送给客户端,此时打印出demo.py文件中的内容,并在本地客户端成功创建一个[接收]demo.py文件

- step2 查看是否存在 [接收]demo.py文件

- step3 查看该文件内容,与demo.py内容一致表示从服务器下载文件成功

- step4 查看Terminal服务器显示,显示出客户端请求下载的文件名正确

3.在服务器目录下存放一张1.jpg头像图片,进行测试
- step1 查看1.jpg文件

- step2 因为该图片大小为42.04K所在在客户端中recv方法的参数值必须大于文件大小值,所以这里我修改为100000,1024=1k,不然的话下载的图片会出现模糊以及残缺
recv_data = tcp_client_socket.recv(100000)
- step3 运行file_download_tcpClient.py程序,向服务器发送下载1.jpg文件请求,

- step4 查看下载后的[接收]1.jpg文件并与1.jpg文件进行对比,属性均一致,表示搭建的tcp文件下载器成功

使用网络TCP搭建一个简单文件下载器的更多相关文章
- springboot搭建一个简单的websocket的实时推送应用
说一下实用springboot搭建一个简单的websocket 的实时推送应用 websocket是什么 WebSocket是一种在单个TCP连接上进行全双工通信的协议 我们以前用的http协议只能单 ...
- 【netty】(2)---搭建一个简单服务器
netty(2)---搭建一个简单服务器 说明:本篇博客是基于学习慕课网有关视频教学.效果:当用户访问:localhost:8088 后 服务器返回 "hello netty"; ...
- 使用gitblit搭建一个简单的局域网服务器
使用gitblit搭建一个简单的局域网服务器 1.使用背景 现在很多使用github管理代码,但是github需要互联网的支持,而且私有的git库需要收费.有一些项目的代码不能外泄,所以,搭建一个局域 ...
- Golang学习-第二篇 搭建一个简单的Go Web服务器
序言 由于本人一直从事Web服务器端的程序开发,所以在学习Golang也想从Web这里开始学起,如果对Golang还不太清楚怎么搭建环境的朋友们可以参考我的上一篇文章 Golang的简单介绍及Wind ...
- Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天、消息模块
原文:Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天.消息模块 中秋节假期没事继续搞了搞 做了各聊天的模块,需要继续优化 第一步画页面 页面参考https://github.c ...
- 用express搭建一个简单的博客系统
转自:https://blog.csdn.net/qq_29721837/article/details/62055603 Express 简介 Express 是一个简洁而灵活的 node.js W ...
- 从零开始搭建一个简单的基于webpack的vue开发环境
原文地址:https://segmentfault.com/a/1190000012789253?utm_source=tag-newest 从零开始搭建一个简单的基于webpack的react开发环 ...
- 超详细,新手都能看懂 !使用SpringBoot+Dubbo 搭建一个简单的分布式服务
来自:JavaGuide Github 地址:https://github.com/Snailclimb/springboot-integration-examples 目录: 使用 SpringBo ...
- 使用 SpringBoot+Dubbo 搭建一个简单分布式服务
实战之前,先来看几个重要的概念 开始实战之前,我们先来简单的了解一下这样几个概念:Dubbo.RPC.分布式.由于本文的目的是带大家使用SpringBoot+Dubbo 搭建一个简单的分布式服务,所以 ...
随机推荐
- C++学习笔记31,指向引用的指针(3)
我们来看一个简单的指向引用的指针的样例. #include <iostream> using namespace std; int main(){ int x=10; int y=20; ...
- JAVA 解析复杂的json字符串
转自:https://blog.csdn.net/lovelovelovelovelo/article/details/73614473String parameter = { success : 0 ...
- OpenGL编程逐步深入(二)在窗口中显示一个点
准备知识 在本文中我们将会接触到OpenGl的扩展库GLEW( OpenGL Extension Wrangler Library),GLEW可以帮助我们处理OpenGl中繁琐的扩展管理.一旦初始化后 ...
- codefroces 650A. Watchmen
A. Watchmen time limit per test 3 seconds memory limit per test 256 megabytes input standard input o ...
- 关于IDEA无法完整显示项目文件结构
今天发现一个奇怪的问题,就是我从本地导入了文件,明明已经成功了,但是在我的项目结构里面就是不显示,然而点击目录, 又能打开相应的文件,如图所示: 其实这个打开的只是包文件,只需要如下图操作即可:
- codevs——T1006 等差数列
http://codevs.cn/problem/1006/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Descr ...
- 具体解释window.location
window.location 对象所包括的属性 hash//从井号 (#) 開始的 URL(锚) host//主机名和当前 URL 的port号 hostname//当前 URL 的主机名 href ...
- VC、IE、ASP环境下打印、预备的完美解决方式
一种基于XML的报表开发工具,它支持从设计报表.调用API打印.预览,能支持分布式报表.方便报表的存储.转发. 在报表中能嵌入VBScript,能方便地訪问VB,VC的变量,能訪问COM组件.ADO等 ...
- BZOJ 3210 花神的浇花集会 计算几何- -?
题目大意:给定平面上的n个点,求一个点到这n个点的切比雪夫距离之和最小 与3170不同的是这次选择的点无需是n个点中的一个 首先将每一个点(x,y)变为(x+y,x-y) 这样新点之间的曼哈顿距离的一 ...
- css3的新特性选择器-------属性选择器
自己学css的时候比较乱,这次趁着复习把css3的新特性选择器和css2以前不怎么用的选择器做一个总结 <div id="parent"> <p>I'm a ...