一、socketserver实现多并发
socket只能实现单进程通讯,要实现多进程同时和服务端通讯就要使用socketserver。
代码如下:
import socket
client = socket.socket()
client.connect(("localhost",9000))
while True:
choice = input(">>>:")
if len(choice) == 0:continue
client.send(choice.encode())
recv = client.recv(1024)
print("recved:",recv.decode())
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Liumj
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
self.data = self.request.recv(1024).strip()
print(self.client_address[0])
print(self.data)
self.request.sendall(self.data.upper())
if __name__ =="__main__":
HOST,PORT = "localhost",9000
server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
server.serve_forever()
二、FTP程序开发
1.服务端代码
import socketserver
import configparser
from conf import settings
import os
import hashlib
import time
t = time.strftime("%H_%M_%S") STATUS_CODE = {
250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}",
251 : "Invalid cmd ",
252 : "Invalid auth data",
253 : "Wrong username or password",
254 : "Passed authentication",
255 : "Filename doesn't provided",
256 : "File doesn't exist on server",
257 : "ready to send file",
258 : "md5 verification",
}
import json
class FTPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
self.data = self.request.recv(1024).strip()
print(self.client_address[0])
print(self.data)
if not self.data:
print("client closed...")
break
data = json.loads(self.data.decode())
if data.get('action') is not None:
print("---->",hasattr(self,"_auth"))
if hasattr(self,"_%s"%data.get('action')):
func = getattr(self,"_%s"% data.get('action'))
func(data)
else:
print("invalid cmd")
self.send_response(251)
else:
print("invalid cmd format")
self.send_response(250) def send_response(self,status_code,data=None):
'''向客户端返回数据'''
response = {'status_code':status_code,'status_msg':STATUS_CODE[status_code]}
if data:
response.update( data )
self.request.send(json.dumps(response).encode()) def _auth(self,*args,**kwargs):
data = args[0]
if data.get("username") is None or data.get("password") is None:
self.send_response(252) user =self.authenticate(data.get("username"),data.get("password"))
if user is None:
self.send_response(253)
else:
print("passed authentication",user)
self.user = user
self.send_response(254)
def authenticate(self,username,password):
'''验证用户合法性,合法就返回用户数据''' config = configparser.ConfigParser()
config.read(settings.ACCOUNT_FILE)
if username in config.sections():
_password = config[username]["Password"]
if _password == password:
print("pass auth..",username)
config[username]["Username"] = username
return config[username] def _put(self,*args,**kwargs):
"client send file to server"
data = args[0]
# if data.get('filename') is None:
# self.send_response(255)
user_home_dir = "%s/%s" % (settings.USER_HOME, self.user["Username"])
file_abs_path = "%s/%s" % (user_home_dir, data.get('filename'))
print("file abs path", file_abs_path)
print("server.....")
self.send_response(257)
received_size = 0
total_size = int(self.request.recv(1024))
file_obj = open(file_abs_path+t, "wb")
#print("zhaodao.....")
while received_size < total_size:
data = self.request.recv(4096)
received_size +=len(data)
file_obj.write(data)
else:
print("---recv done...")
file_obj.close() def _get(self,*args,**kwargs):
data = args[0]
if data.get('filename') is None:
self.send_response(255)
user_home_dir = "%s/%s" %(settings.USER_HOME,self.user["Username"])
file_abs_path = "%s/%s" %(user_home_dir,data.get('filename'))
print("file abs path",file_abs_path) if os.path.isfile(file_abs_path):
file_obj = open(file_abs_path,"rb")
file_size = os.path.getsize(file_abs_path)
self.send_response(257,data={'file_size':file_size})
self.request.recv(1) #等待客户端确认 if data.get('md5'):
md5_obj = hashlib.md5()
for line in file_obj:
self.request.send(line)
md5_obj.update(line)
else:
file_obj.close()
md5_val = md5_obj.hexdigest()
self.send_response(258,{'md5':md5_val})
print("send file done....")
else:
for line in file_obj:
self.request.send(line)
else:
file_obj.close()
print("send file done....")
else:
self.send_response(256) def _ls(self,*args,**kwargs):
pass def _cd(self, *args, **kwargs):
pass if __name__ == "__main__":
HOST, PORT = "localhost", 9000
ftp_server
2.客户端代码
import socket
import os ,json
import optparse
import getpass
import hashlib
import sys STATUS_CODE = {
250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}",
251 : "Invalid cmd ",
252 : "Invalid auth data",
253 : "Wrong username or password",
254 : "Passed authentication",
255 : "Filename doesn't provided",
} class FTPClient(object):
def __init__(self):
parser = optparse.OptionParser()
parser.add_option("-s","--server", dest="server", help="ftp server ip_addr")
parser.add_option("-P","--port",type="int", dest="port", help="ftp server port")
parser.add_option("-u","--username", dest="username", help="username")
parser.add_option("-p","--password", dest="password", help="password")
self.options , self.args = parser.parse_args()
self.verify_args(self.options,self.args)
self.make_connection() def make_connection(self):
self.sock = socket.socket()
self.sock.connect((self.options.server,self.options.port)) def verify_args(self, options,args):
'''校验参数合法型'''
if options.username is not None and options.password is not None:
pass
elif options.username is None and options.password is None:
pass
else:
#options.username is None or options.password is None:
exit("Err: username and password must be provided together..") if options.server and options.port:
#print(options)
if options.port >0 and options.port <65535:
return True
else:
exit("Err:host port must in 0-65535") def authenticate(self):
'''用户验证'''
if self.options.username:
print(self.options.username,self.options.password)
return self.get_auth_result(self.options.username, self.options.password)
else:
retry_count = 0
while retry_count <3:
username = input("username:").strip()
password = input("password:").strip()
return self.get_auth_result(username,password) def get_auth_result(self,user,password):
data = {'action':'auth',
'username':user,
'password':password} self.sock.send(json.dumps(data).encode())
response = self.get_response()
if response.get('status_code') == 254:
print("Passed authentication!")
self.user = user
return True
else:
print(response.get("status_msg")) def get_response(self):
'''得到服务器端回复结果'''
data = self.sock.recv(1024)
print("server res", data)
data = json.loads(data.decode())
return data def interactive(self):
if self.authenticate():
print("---start interactive iwth u...")
while True:
choice = input("[%s]:"%self.user).strip()
if len(choice) == 0:continue
cmd_list = choice.split()
if hasattr(self,"_%s"%cmd_list[0]):
func = getattr(self,"_%s"%cmd_list[0])
func(cmd_list)
else:
print("Invalid cmd.") def __md5_required(self,cmd_list):
'''检测命令是否需要进行MD5验证'''
if '--md5' in cmd_list:
return True
def show_progress(self,total):
received_size = 0
current_percent = 0
while received_size < total:
if int((received_size / total) * 100 ) > current_percent :
print("#",end="",flush=True)
current_percent = int((received_size / total) * 100 )
new_size = yield
received_size += new_size
def _get(self,cmd_list):
print("get--",cmd_list)
if len(cmd_list) == 1:
print("no filename follows...")
return
data_header = {
'action':'get',
'filename':cmd_list[1]
}
if self.__md5_required(cmd_list):
data_header['md5'] = True self.sock.send(json.dumps(data_header).encode())
response = self.get_response()
print(response)
if response["status_code"] ==257:#ready to receive
self.sock.send(b'')#send confirmation to server
base_filename = cmd_list[1].split('/')[-1]
received_size = 0
file_obj = open(base_filename,"wb")
if self.__md5_required(cmd_list):
md5_obj = hashlib.md5()
progress = self.show_progress(response['file_size']) #generator
progress.__next__()
while received_size < response['file_size']:
data = self.sock.recv(4096)
received_size += len(data)
try:
progress.send(len(data))
except StopIteration as e:
print("100%")
file_obj.write(data)
md5_obj.update(data)
else:
print("----->file rece done----")
file_obj.close()
md5_val = md5_obj.hexdigest()
md5_from_server = self.get_response()
if md5_from_server['status_code'] == 258:
if md5_from_server['md5'] == md5_val:
print("%s 文件一致性校验成功!" % base_filename)
#print(md5_val,md5_from_server) else:
progress = self.show_progress(response['file_size']) #generator
progress.__next__() while received_size < response['file_size']:
data = self.sock.recv(4096)
received_size += len(data)
file_obj.write(data)
try:
progress.send(len(data))
except StopIteration as e:
print("100%") else:
print("----->file recv done----")
file_obj.close()
def _put(self,cmd_list):
print("put----",cmd_list)
if len(cmd_list) == 1:
print("no filename follows...")
return
data_header = {
'action':'put',
'filename':cmd_list[1]
}
self.sock.send(json.dumps(data_header).encode())
#response = self.get_response()
#print(response)
print("client......")
file_obj = open(cmd_list[1],"rb")
file_size = os.stat(cmd_list[1]).st_size
print(file_size)
self.sock.send(str(file_size).encode())
self.sock.recv(1024) #等待服务端确认
progress = self.show_progress(file_size) # generator
progress.__next__()
for i in file_obj:
self.sock.send(i)
else:
try:
progress.send(int(file_size))
except StopIteration as e:
print("100%")
file_obj.close()
print("send done...")
if __name__ == "__main__":
ftp = FTPClient()
ftp.interactive() #交互
ftp_client