码迷,mamicode.com
首页 > 其他好文 > 详细

网络编程(九)

时间:2018-05-31 23:05:01      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:filename   handle   family   udp   serve   模块   exception   nes   res   

threading并发服务器


相比多进程服务器的优缺点:
缺点: 1. 需要用到同步互斥
2. 可能受到GIL的影响,但是网络IO线程并发还是可以的
优点: 资源消耗比较少


使用模块 : threading socket

步骤
1. 创建套接字 绑定 监听
2. 接收客户端连接请求 创建新的线程
3. 主线程继续接收下一个客户端连接请求,分支线程处理客户端事件
4. 处理事件结束,退出线程,关闭套接字


基于并发的HttpServer

1.使用并发方案,有助于建立长连接
2.用线程完成并发消耗更小资源
3.将服务器功能封装为类
4.静态网页放在一个专门的文件夹中管理
5.使用不同的模块处理客户端请求,这些放在一个文件夹中

技术实现 :
并发 : 多线程
server 类的设计 :
初始化 : 将socket返回值变为属性 并且增加一系列其他属性

服务器启动方法 : 接受客户端连接请求,创建新的线程

客户端处理函数 : handleRrequest

cookie:
sys.path : 是一个列表,可以添加路径。该列表中的路径,对python下的所有环境可见
__import__() : 参数为一个目录, 等同于import 导入


使用集成模块完成网络并发

python3 ---》 socketserver 模块

进程tcp并发 ‘ForkingMixIn‘,‘TCPServer‘,‘StreamRequestHandler‘

进程udp并发
‘ForkingMixIn‘ ‘UDPServer‘,‘DatagramRequestHandler‘,

线程tcp并发
‘ThreadingMixIn‘ ‘TCPServer‘,‘StreamRequestHandler‘

线程udp并发
‘ThreadingMixIn‘, ‘UDPServer‘,‘DatagramRequestHandler‘,

‘ForkingTCPServer‘,
‘ForkingUDPServer‘,
‘ThreadingTCPServer‘,
‘ThreadingUDPServer‘,


**********************************************************************************
这是一个http服务器
‘‘‘
1.实现了多线程并发
2.讲server的创建部分封装为类
3.后端可以处理不同的请求 
‘‘‘
from socket import *
from threading import Thread
import sys

ADDR = (‘0.0.0.0‘,8000)
static_root = ‘./static‘
handler_root = ‘./handler‘

#httpserver 类
class HTTPServer(object):
def __init__(self,addr):
self.sockfd = socket()
self.sockfd.setsockopt\
(SOL_SOCKET,SO_REUSEADDR,1)
self.sockfd.bind(addr)
self.sockfd.listen(5)
self.serveName = ‘127.0.0.1‘
self.servePort = 8000

#服务器启动函数 : 接受客户端请求,创建新的线程
def serveForever(self):
while True:
self.connfd,self.clientAddr =\
self.sockfd.accept()
clientThread = Thread\
(target = self.handleRequest)
clientThread.start()

def setApp(self,application):
self.application = application

def handleRequest(self):
#接收request请求
self.recvData = self.connfd.recv(2048)
requestHeaders = self.recvData.splitlines()
for line in requestHeaders:
print(line)

#获取到从浏览器输入的具体请求
getRequest = \
str(requestHeaders[0]).split(‘ ‘)[1]

if getRequest[-3:] != ‘.py‘:
if getRequest == ‘/‘:
getFilename = static_root + "/index.html"
else:
getFilename = static_root + getRequest

try:
f = open(getFilename)
except:
responseHeaders = "HTTP/1.1 404 not found\r\n"
responseHeaders += "\r\n"
responseBody = "====sorry,file not find====="
else:
responseHeaders = "HTTP/1.1 200 OK\r\n"
responseHeaders += "\r\n"
responseBody = f.read()
finally:
response = responseHeaders + responseBody
self.connfd.send(response.encode())
else:
#需要的环境变量
env = {}
bodyContent = self.application\
(env,self.startResponse)

response = "HTTP/1.1 {}\r\n".format(self.header_set[0])
for header in self.header_set[1:]:
response += "{0}:{1}\r\n".format(*header)
response += ‘\r\n‘
response += bodyContent
self.connfd.send(response.encode())

self.connfd.close()

def startResponse(self,status,response_headers):
serverHeaders = [
(‘Date‘,‘2018-5-21‘),
(‘Server‘,"HTTPServer 1.0"),
]
self.header_set = \
[status,response_headers + serverHeaders]


#控制服务器启动
def main():
# 启动时直接告知使用哪个模块哪个函数处理请求
# python3 HttpServer.py module app
if len(sys.argv) < 3:
sys.exit("请选择一个模块和应用")
#将handler文件夹加入搜索路径
sys.path.insert(0,handler_root)
#导入module模块
m = __import__(sys.argv[1])
#获取module 下的app 付给一个变量
application = getattr(m,sys.argv[2])

httpd = HTTPServer(ADDR)
httpd.setApp(application)
print("Serving HTTP on port 8000")
httpd.serveForever()

if __name__ == "__main__":
main()


****************************************************************************
#多进程tcp 

from socketserver import *

#创建服务器类
# class Server(ForkingTCPServer)
class Server(ForkingMixIn,TCPServer):
pass

#处理具体请求
class Handler(StreamRequestHandler):
def handle(self):
#self.request 相当于 accept创建的新的套接字
addr = self.request.getpeername()
print("Connect from",addr)
while True:
data = self.request.recv(1024).decode()
if not data:
break
self.request.send(b"receive your message")

server = Server((‘0.0.0.0‘,9999),Handler)
server.serve_forever()

************************************************************************
#!/usr/bin/python

import socket,os,sys,traceback
from threading import *

host = ‘192.168.1.211‘
port = 9999

def handler(clientsock):
print (‘New child‘)
print(‘Got connection from‘,clientsock.getpeername())
while True:
data = clientsock.recv(1024).decode()
if not len(data):
break
clientsock.send(‘receive your message‘.encode())

clientsock.close()

s = socket.socket()
s.bind((host,port))
s.listen(5)

while True:
try:
clientsock,clientaddr = s.accept()
except KeyboardInterrupt:
raise
except:
traceback.print_exc()
continue

t = Thread(target = handler,args = (clientsock,))
t.setDaemon(1)
t.start()

s.close()

******************************************************************************
from socket import *
import os
import sys
import signal
import time

FILE_PATH = "/home/tarena/"

class FtpServer(object):
def __init__(self,connfd):
self.connfd = connfd

def do_list(self):
filelist = os.listdir(FILE_PATH)
#服务器确认请求是否可以执行
if filelist == None:
self.connfd.send(b"FALL")
self.connfd.send(b‘OK‘)
time.sleep(0.1)
for filename in filelist:
if filename[0] != ‘.‘ and os.path.isfile(FILE_PATH + filename):
self.connfd.send(filename.encode())
time.sleep(0.1)
self.connfd.send(b"##")
print(‘文件列表发送完毕‘)
return

def do_get(self,filename):
try:
fd = open(FILE_PATH+filename,‘rb‘)
except:
self.connfd.send(b"FALL")
self.connfd.send(b‘OK‘)
time.sleep(0.1)
for line in fd:
self.connfd.send(line)
fd.close()
time.sleep(0.1)
self.connfd.send(b‘##‘)
print("文件发送成功")
return

def do_put(self,filename):
try:
fd = open(FILE_PATH+filename,‘w‘)
except:
self.connfd.send(b"FALL")
self.connfd.send(b‘OK‘)
while True:
data = self.connfd.recv(1024).decode()
if data == ‘##‘:
break
fd.write(data)
fd.close()
print("接收文件完毕")
return

def main():
if len(sys.argv) != 3:
print("argv is error")
sys.exit(1)
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
BUFFERSIZE = 1024

sockfd = socket()
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(0)
except Exception:
continue
print("客户端登录:",addr)
pid = os.fork()
if pid < 0:
print("创建子进程失败")
continue
elif pid == 0:
sockfd.close()
ftp = FtpServer(connfd)
#接收客户端请求
while True:
data = connfd.recv(BUFFERSIZE).decode()
if data[0] == ‘L‘:
ftp.do_list()
elif data[0] == ‘G‘:
filename = data.split(‘ ‘)[-1]
ftp.do_get(filename)
elif data[0] == "P":
filename = data.split(‘ ‘)[-1]
ftp.do_put(filename)
elif data[0] == "Q":
print("客户端退出")
sys.exit(0)

else:
connfd.close()
continue


if __name__ == "__main__":
main()

***********************************************************************
from socket import *
import sys
import time

class FtpClient(object):
def __init__(self,sockfd):
self.sockfd = sockfd

def do_list(self):
self.sockfd.send(b"L") #发送请求类型
#接收服务器确认 OK or FALL
data = self.sockfd.recv(1024).decode()
if data == ‘OK‘:
while True:
data = self.sockfd.recv(1024).decode()
if data == ‘##‘:
break
print(data)
print("文件列表展示完毕")
return
else:
print("文件列表请求失败")
return

def do_get(self,filename):
self.sockfd.send(("G " + filename).encode())
#接收服务器确认 OK or FALL
data = self.sockfd.recv(1024).decode()
if data == ‘OK‘:
fd = open(filename,‘w‘)
while True:
data = self.sockfd.recv(1024).decode()
if data == ‘##‘:
break
fd.write(data)
fd.close()
print(‘%s 下载完成‘%filename)
return
else:
print("下载文件失败")
return

def do_put(self,filename):
try:
fd = open(filename,‘rb‘)
except:
print("上传的文件不存在")
return
self.sockfd.send(("P " + filename).encode())
#接收服务器确认 OK or FALL
data = self.sockfd.recv(1024).decode()
if data == ‘OK‘:
for line in fd:
self.sockfd.send(line)
fd.close()
time.sleep(0.1)
self.sockfd.send(b"##")
print("上传文件 %s 完成"%filename)
return
else:
print("上传文件失败")
return

def do_quit(self):
self.sockfd.send(b"Q")

def main():
if len(sys.argv) != 3:
print("argv is error")
sys.exit(1)
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
BUFFERSIZE = 1024
sockfd = socket()
sockfd.connect(ADDR)

ftp = FtpClient(sockfd) #生产事件对象

while True:
print("********命令选项**********")
print("******** list************")
print("******** get file********")
print("******** put file********")
print("******** quit************")
data = input("输入命令>>")

if data[:4] == ‘list‘:
ftp.do_list()
elif data[:3] == ‘get‘:
filename = data.split(‘ ‘)[-1]
ftp.do_get(filename)
elif data[:3] == ‘put‘:
filename = data.split(‘ ‘)[-1]
ftp.do_put(filename)
elif data[:4] == ‘quit‘:
ftp.do_quit()
sockfd.close()
sys.exit(0)
else:
print("请输出正确命令!!!")
continue


if __name__ == "__main__":
main()


***********************************************************************
import time
#处理特定请求的模块
def app(environ,start_response):
status = ‘200 OK‘
response_headers =\
[(‘Content-Type‘,‘text/plain;charset=UTF-8‘)]

start_response(status,response_headers)

return "\n====简单的app程序===\n%s"%time.ctime()
***********************************************************************

网络编程(九)

标签:filename   handle   family   udp   serve   模块   exception   nes   res   

原文地址:https://www.cnblogs.com/wcin/p/9119238.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!