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实现 这是一个极其简单 ...
随机推荐
- java GZIP 压缩数据
package com.cjonline.foundation.cpe.action; import java.io.ByteArrayInputStream; import java.io.Byte ...
- Angularjs实例3
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- Struts2 第五讲 -- Struts2与Servlet的API解耦
为了避免与 Servlet API 耦合在一起, 方便 Action 做单元测试, Struts2 对 HttpServletRequest, HttpSession 和 ServletContext ...
- 菜鸟笔记 -- Chapter 6.2 类的构成
在前面我们讲过高级开发语言大多由7种语法构成,但这是一个很空泛的概述,下,面我们仅就针对Java程序来说一下构成一个Java程序的几大部分,其中类是最小的基本元素.类是封装对象属性和行为的载体,而在J ...
- Struts2前期(这框架目前正处于淘汰状态)
Struts2第一天 Struts2的学习路线 1. Struts2的入门:主要是学习Struts2的开发流程(Struts2的开发流程.常见的配置.Action类的编写) 2. Struts2的Se ...
- CentOS 7 以上防火墙简单配置
CentOS 7 版本以上默认的防火墙不是iptables,而是firewalle. 因此CentOS 7 以下的 iptables 的配置不能使用. 查看防火墙状态: systemctl statu ...
- date 参数(option)-d
记录这篇博客的原因是:鸟哥的linux教程中,关于date命令的部分缺少-d这个参数的介绍,并且12章中的shell编写部分有用到-d参数 date 参数(option)-d与--date=" ...
- xpath技术解析xm文件(php)
1.结合php dom技术的学习,得出一个结论:php dom技术可以跨层取出节点,但是不能保持层次关系,使用xpath可以很好地解决问题. *** xpath技术的核心思想:迅速简洁的定位你需要查找 ...
- jquery点击li 获取当前父节点所在类的索引
jquery点击li 获取当前父节点所在类的索引 $('.jbcz').find('.content li').click(function(){ //alert($('.jbcz').find('. ...
- sql语句中#{}和${}的区别
#---将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的 ...