Python网络编程(socketserver、TFTP云盘、HTTPServer服务器模型)
HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。
通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS
默认HTTP的端口号为80,HTTPS的端口号为443。
from socket import *
import os
import signal
import sys
import time # 文件库
FILE_PATH = "/home/tarena/" # 实现功能模块
class TftpServer(object):
def __init__(self,connfd):
self.connfd = connfd # 查询
def do_list(self):
# 获取列表
file_list = os.listdir(FILE_PATH)
if not file_list:
self.connfd.send("文件库为空".encode())
# 服务器目录无文件
return
else:
# 有文件
self.connfd.send(b'OK')
time.sleep(0.1) files = ""
for file in file_list:
# 发送所有普通文件的文件名并且不是隐藏文件
if os.path.isfile(FILE_PATH+file) and file[0] != '.':
# 文件名间隔符 用于客户端解析
files = files + file + '#'
# 一次全部发送 简单粗暴
self.connfd.send(files.encode()) # 下载
def do_get(self,filename):
# 判断文件是否纯在
try:
fd = open(FILE_PATH + filename,'rb')
except:
self.connfd.send("文件不存在".encode())
return
self.connfd.send(b'OK')
time.sleep(0.1)
# 发送文件
try:
while True:
data = fd.read(1024)
if not data:
break
self.connfd.send(data)
except Exception as e:
print(e)
time.sleep(0.1)
self.connfd.send(b'##') # 表示文件发送完成
print("文件发送完毕") # 上传
def do_put(self,filename):
# 限制文件命重复导致覆盖源文件
try:
fd = open(FILE_PATH+filename,'xb')
except:
self.connfd.send("无法上传".encode())
return
except FileExistsError:
self.connfd.send("文件已存在".encode())
return
self.connfd.send(b'OK')
# 上传文件
while True:
data = self.connfd.recv(1024)
if data == b'##':
break
fd.write(data)
fd.close()
print("文件上传完毕") # 流程控制,创建套接字,创建并发,方法调用
def main():
HOST = '0.0.0.0'
PORT = 8888
ADDR = (HOST,PORT)
# 创建套接字
sockfd = socket()
sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sockfd.bind(ADDR)
sockfd.listen(5)
# 忽略子进程退出
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
# 循环等待客户端链接
while True:
try:
connfd, addr = sockfd.accept()
except KeyboardInterrupt:
sockfd.close()
sys.exit("服务器退出")
except Exception as e:
print(e)
continue
print("客户端登录:",addr) # 创建父子进程
pid = os.fork()
# 进入子进程
if pid == 0:
# 关闭子进程内无用套接字
sockfd.close()
tftp = TftpServer(connfd) # __init__传参
while True:
data = connfd.recv(1024).decode()
# 断开连接
if (not data) or data[0] == 'Q':
print("客户端退出")
sys.exit(0)
elif data[0] == "L":
# 申请查询
tftp.do_list()
elif data[0] == 'G':
# 解析文件名
filename = data.split(' ')[-1]
# 申请下载
tftp.do_get(filename)
elif data[0] == 'P':
filename = data.split(' ')[-1]
# 申请上传
tftp.do_put(filename)
else:
print("客户端发送错误指令")
else:
# 关闭父进程内无用套接字
connfd.close()
# 父进程只用来做客户端链接
continue if __name__ == "__main__":
main()
from socket import *
import sys
import time # 实现各种功能请求
class TftpClient(object):
def __init__(self,sockfd):
self.sockfd = sockfd def do_list(self):
self.sockfd.send(b'L') # 发送请求类型
# 接收服务器回应
data = self.sockfd.recv(1024).decode()
if data == "OK":
data = self.sockfd.recv(4096).decode()
files = data.split('#')
for file in files:
print(file)
print("文件展示完毕")
else:
# 请求失败原因
print(data) # 下载指定文件
def do_get(self,filename):
self.sockfd.send(('G ' + filename).encode())
data = self.sockfd.recv(1024).decode()
# 请求成功
if data == 'OK':
fd = open(filename,'wb')
while True:
data = self.sockfd.recv(1024)
# 结束符
if data == b'##':
break
fd.write(data)
fd.close()
print("%s 下载完成\n"%filename)
else:
# 请求失败原因
print(data) def do_put(self,filename):
# 判断本地是否有要上传的文件
try:
fd = open(filename,'rb')
except:
print("上传文件不存在")
return
self.sockfd.send(("P "+filename).encode())
data = self.sockfd.recv(1024).decode()
# 请求成功
if data == 'OK':
while True:
data = fd.read(1024)
if not data:
break
self.sockfd.send(data)
fd.close()
# 发送结束符并防止粘包
time.sleep(0.1)
self.sockfd.send(b'##')
print("%s 上传完毕"%filename)
else:
# 请求失败原因
print(data) # 创建套接字并建立连接
def main():
# 终端输入地址
if len(sys.argv) < 3:
print("argv is error")
return
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT) sockfd = socket()
sockfd.connect(ADDR)
# 创建对象
tftp = TftpClient(sockfd) while True:
print("")
print("==========命令选项===========")
print("********** list *********")
print("********** get file ******")
print("********** put file ******")
print("********** quit *********")
print("=============================") cmd = input("输入命令>>")
# 去除空格判断命令
if cmd.strip() == "list":
# 查询
tftp.do_list()
# 获取文件上传或下载命令
elif cmd[:3] == "get":
# 拆分命令获取文件名
filename = cmd.split(' ')[-1]
# 下载
tftp.do_get(filename)
elif cmd[:3] == "put":
filename = cmd.split(' ')[-1]
# 上传
tftp.do_put(filename)
# 退出
elif cmd.strip() == "quit":
sockfd.send(b'Q')
sockfd.close()
sys.exit("欢迎使用")
else:
print("请输入正确命令!") if __name__ == "__main__":
main() 多线程并发 threading模块完成多线程并发 对比多进程并发
优势 :
资源消耗少
缺点 :
需要注意对共享资源的操作 实现步骤:
1. 创建套接字,绑定,监听
2. 接收客户端连接请求,创建新的线程
3. 主线程继续等待其他客户端连接,分支线程执行客户端具体请求
4. 处理完客户端请求后分支线程自然退出,关闭客户端套接字
示例: from socket import *
import os,sys
from threading import * HOST = "0.0.0.0"
PORT = 8888
ADDR = (HOST,PORT) #客户端处理函数
def handler(connfd):
print("Connect from",connfd.getpeername())
while True:
data = connfd.recv(1024).decode()
if not data:
break
print(data)
connfd.send(b'Receive your msg')
connfd.close() def main(ADDR):
s = socket()
s.bind(ADDR)
s.listen(5) while True:
try:
connfd,addr = s.accept()
# 处理 Ctrl + C
except KeyboardInterrupt:
s.close()
sys.exit("服务器退出")
# 其他异常
except Exception as e:
print(e)
continue
# 创建子线程用于处理客户端请求
t = Thread(target=handler,args= (connfd,))
t.setDaemon(True)
t.start() if __name__ == __main__:
main()
#多进程 tcp server
from socketserver import * #创建server类
# class Server(ForkingMixIn,TCPServer):
# class Server(ForkingTCPServer):
# pass #多线程tcp并发
class Server(ThreadingTCPServer):
pass #具体的请求处理类
class Handler(StreamRequestHandler):
def handle(self):
# self.request ==> accept返回的套接字
print("Connect from",self.request.getpeername())
while True:
data = self.request.recv(1024).decode()
if not data:
break
print(data)
self.request.send(b'Receive') if __name__ == __main__:
#创建server对象
server = Server(("0.0.0.0",8888),Handler) #启动服务器
server.serve_forever()
from socket import *
from threading import Thread
import time # 存放静态页面的目录
STATIC_DIR = "./static"
ADDR = ('0.0.0.0', 8000) # HTTPServer类,封装具体功能
class HTTPServer(object):
def __init__(self, address):
# 创建套接字
self.sockfd = socket()
# 设置端口重用
self.sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self.sockfd.bind(address)
self.sockfd.listen(5)
# 为对象增加属性变量
self.name = "HTTPServer"
self.port = address[1]
self.address = address # 启动服务器
def serve_forever(self):
print("Listen the port %d"%self.port)
while True:
# 循环接收客户端请求并创建新的套接字
connfd, addr = self.sockfd.accept()
# 创建线程并运行处理具体请求
clientThread = Thread(target = self.handleRequest,args = (connfd,))
# 主线程结束时结束线程
clientThread.setDaemon(True)
clientThread.start() def handleRequest(self, connfd):
# 接收客户端请求
request = connfd.recv(4096)
# 按行切割 字符串
requestHeadlers = request.splitlines()
# 获取请求行
print(connfd.getpeername(), ":" , requestHeadlers[0])
# 获取请求内容并解析
getRequest = str(requestHeadlers[0]).split(' ')[1]
# 并判断请求类型
if getRequest == '/' or getRequest[-5:] == '.html':
# 请求行为网页请求
data = self.get_html(getRequest)
else:
# 请求指定数据内容
data = self.get_data(getRequest)
# 响应请求并返还内容
connfd.send(data.encode())
connfd.close() # 用于处理网页请求
def get_html(self,page):
# 判断是否为主页请求
if page == "/":
filename = STATIC_DIR + "/index.html"
else:
filename = STATIC_DIR + page try:
f = open(filename)
except Exception:
# 没有找到页面
responseHeadlers = "HTTP/1.1 404 Not Found\r\n"
responseHeadlers += "Content-Type: text/html\r\n"
responseHeadlers += '\r\n'
responseBody = "<h1>Sorry,not found the page</h1>"
else:
responseHeadlers = "HTTP/1.1 200 OK\r\n"
responseHeadlers += "Content-Type: text/html\r\n"
responseHeadlers += '\r\n'
for i in f:
responseBody += i
# 页面存不存在否响应
finally:
return responseHeadlers + responseBody # 用于处理数据内容请求
def get_data(self,data):
responseHeadlers = "HTTP/1.1 200 OK\r\n"
responseHeadlers += "\r\n" if data == "/time":
responseBody = time.ctime()
elif data == "/ParisGabriel":
responseBody = "Welcome to ParisGabriel"
else:
responseBody = "The data not found"
return responseHeadlers + responseBody if __name__ == "__main__":
# 生成服务器对象
httpd = HTTPServer(ADDR)
# 启动服务器
httpd.serve_forever()
Python网络编程(socketserver、TFTP云盘、HTTPServer服务器模型)的更多相关文章
- python网络编程socketserver模块(实现TCP客户端/服务器)
摘录python核心编程 socketserver(python3.x版本重新命名)是标准库中的网络编程的高级模块.通过将创建网络客户端和服务器所必须的代码封装起来,简化了模板,为你提供了各种各样的类 ...
- Python网络编程基础|百度网盘免费下载|零基础入门学习资料
百度网盘免费下载:Python网络编程基础|零基础学习资料 提取码:k7a1 目录: 第1部分 底层网络 第1章 客户/服务器网络介绍 第2章 网络客户端 第3章 网络服务器 第4章 域名系统 第5章 ...
- python网络编程——SocketServer/Twisted/paramiko模块
在之前博客C/S架构的网络编程中,IO多路复用是将多个IO操作复用到1个服务端进程中进行处理,即无论有多少个客户端进行连接请求,服务端始终只有1个进程对客户端进行响应,这样的好处是节省了系统开销(se ...
- python网络编程--socketserver 和 ftp功能简单说明
1. socketserver 我们之前写的tcp协议的socket是不是一次只能和一个客户端通信,如果用socketserver可以实现和多个客户端通信.它是在socket的基础上进行了一层封装,也 ...
- python网络编程-socketserver
一:socketserver简化了网络服务器的编写. 它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer. 这4个类是同步进行处 ...
- python 网络编程(socketserver,阻塞,其他方法)
重点回顾: (重点)粘包 : 就是因为接收端不知道如何接收数据,造成接收数据的混乱的问题 只发生在tcp协议上. 因为tcp协议的特点是面向数据流形式的传输 粘包的发生主要是因为tcp协议有两个机制: ...
- python网络编程-socketserver模块
使用socketserver 老规矩,先引入import socketserver 必须创建一个类,且继承socketserver.BaseRequestHandler 这个类中必须重写handle( ...
- Python网络编程03 /缓存区、基于TCP的socket循环通信、执行远程命令、socketserver通信
Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命令.socketserver通信 目录 Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命 ...
- Python网络编程基础 PDF 完整超清版|网盘链接内附提取码下载|
点此获取下载地址提取码:y9u5 Python网络编程最好新手入门书籍!175个详细案例,事实胜于雄辩,Sockets.DNS.Web Service.FTP.Email.SMTP.POP.IMAP. ...
- Python 网络编程(二)
Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...
随机推荐
- NodeJS学习日记--环境配置及项目初始化
在node.js官网下载nodejs安装包 安装完成后打开控制台,输入 npm -version 如果正确显示npm版本则安装成功. 创建项目之前先要安装以下全局扩展模块 npm install -g ...
- JVM 监控以及内存分析
1 内存分析1.1 jmap -histo 命令pid=`jps | awk '{if ($2 == "Jps") print $1}'`jmap -histo $pid > ...
- Code First 一
Code-First和我们的数据库优先方式是相反的,数据库优先是通过数据库映射出相应的类和上下文,Code-First测试通过创建的类和上下文得到相应的数据库. Code-First主要用于领域驱动设 ...
- 到底什么时候需要使用 final
final: final修饰属性,则该属性不可再次改变,而且在初始化中必须在属性或者是构造方法中其中且中有一个中初始化他 final修饰方法,则该方法不可被重写 final修饰类,则不可被继承 1:当 ...
- o'Reill的SVG精髓(第二版)学习笔记——第八章
第八章:图案和渐变 要使用图案,首先要定义一个水平或者垂直方向重复的图形对象,然后用它填充另一个对象或者作为笔画使用.这个图形对象呗称作tile(瓷砖). 下面可以把SVG绘制的二次曲线作为图案. & ...
- 数据库——MySQL——存储引擎
现实生活中我们用来存储数据的文件有不同的类型,每种文件类型对应各自不同的处理机制:比如处理文本用txt类型,处理表格用excel,处理图片用png等.数据库中的表也应该有不同的类型,表的类型不同,会对 ...
- 取消Eclipse的自动代码格式化
前段时间在Eclipse里面设置了java文件保存时自动格式化,在java->Code Style->Formatter里设置了自定义的格式化的样式,这样每次保存后都会自动格式化代码,用了 ...
- java程序执行命令行,解锁数据库表
有些表锁的时间长或其他原因,在plsql中不能解锁,只能用命令行解锁. 有些功能跨平台系统的交互偶尔会锁表,就需要自动解锁. 下面是解锁的代码: package com.lg.BreakOracleU ...
- webBrowser 应用编程函数总结
/*============================说明部分================================= 实现一下函数需包含头文件 #include <Winine ...
- ECSHOP和SHOPEX快递单号查询顺丰插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...