python--socket(二)粘着バッグ
27253 ワード
パケット問題とは,受信者がメッセージ間の境界を知らず,一度に何バイトのデータを抽出するか分からないためである.
また、送信側による粘着パケットは、TCPプロトコル自体によるものであり、TCPは
高い伝送効率で、送信側は往々にして十分なデータを収集してからTCPを送信する.
セグメント.連続してsendを必要とするデータが少ない場合、通常TCPは最適化に基づいて計算されます.
法はこれらのデータを1つのTCPセグメントを合成した後に一回送信して、このように受信者は受け取ります
データを貼り付けました.
TCP(transport control protocol、トランスポート制御プロトコル)は接続向け
は、ストリーム向けで、高信頼性のサービスを提供します.送受信の両端(クライアントとサーバ側)
)はいずれも1対1のソケットが必要であるため,送信側は複数を受信側に送信するために
のパッケージは、相手により効果的に送信され、最適化方法(Nagleアルゴリズム)を使用して、複数の
サブ間隔が小さく、データ量の少ないデータを大きなブロックに結合し、
封をする.このように、受信側は、見分けがつかず、科学的な分解機を提供しなければならない.
を作成します.すなわち、ストリーム向けの通信は、メッセージ保護境界がない.UDP(user datagram protocol、ユーザーデータレポートプロトコル)は接続されていません
、メッセージ向け、効率的なサービスを提供します.ブロックのマージ最適化アルゴリズムは使用されません.
UDPでは一対多のモードがサポートされているので、受信側のskbuff(ソケットバッファ)
)各到着UDPパケットを記録するためにチェーン構造が採用されており、各UDPパケットには
メッセージヘッダ(メッセージソースアドレス、ポートなどの情報)があり、受信に対して
端的に言えば、区分処理が容易になります.すなわち、メッセージ向けの通信はメッセージ保証付きである
境界を守る.tcpはデータストリームに基づいているため、受信されたメッセージを空にすることはできません.これは、お客様が
エンドとサービスエンドは空のメッセージの処理メカニズムを追加し、プログラムの詰まりを防止し、udpはベースである.
データによると、あなたが空の内容を入力しても(直接車に戻る)、それはそうではありません.
空のメッセージ、udpプロトコルはメッセージヘッダをカプセル化します.
udpのrecvfromはブロックされており、1つのrecvfrom(x)は1つに対して1つでなければならない.
sendinto(y)は、xバイトのデータを受信して完了してもy>xのデータが失われ、
これはudpがパケットにくっつかないことを意味しますが、データが失われ、信頼できないtcpのプロトコルデータが失われず、パケットが受信されず、次回受信し、前回継続します.
受信すると、自己側は常にackを受信するとバッファの内容をクリアします.データは信頼できる
あ、でもべたべたします.
==============================================
FTP
client
また、送信側による粘着パケットは、TCPプロトコル自体によるものであり、TCPは
高い伝送効率で、送信側は往々にして十分なデータを収集してからTCPを送信する.
セグメント.連続してsendを必要とするデータが少ない場合、通常TCPは最適化に基づいて計算されます.
法はこれらのデータを1つのTCPセグメントを合成した後に一回送信して、このように受信者は受け取ります
データを貼り付けました.
TCP(transport control protocol、トランスポート制御プロトコル)は接続向け
は、ストリーム向けで、高信頼性のサービスを提供します.送受信の両端(クライアントとサーバ側)
)はいずれも1対1のソケットが必要であるため,送信側は複数を受信側に送信するために
のパッケージは、相手により効果的に送信され、最適化方法(Nagleアルゴリズム)を使用して、複数の
サブ間隔が小さく、データ量の少ないデータを大きなブロックに結合し、
封をする.このように、受信側は、見分けがつかず、科学的な分解機を提供しなければならない.
を作成します.すなわち、ストリーム向けの通信は、メッセージ保護境界がない.UDP(user datagram protocol、ユーザーデータレポートプロトコル)は接続されていません
、メッセージ向け、効率的なサービスを提供します.ブロックのマージ最適化アルゴリズムは使用されません.
UDPでは一対多のモードがサポートされているので、受信側のskbuff(ソケットバッファ)
)各到着UDPパケットを記録するためにチェーン構造が採用されており、各UDPパケットには
メッセージヘッダ(メッセージソースアドレス、ポートなどの情報)があり、受信に対して
端的に言えば、区分処理が容易になります.すなわち、メッセージ向けの通信はメッセージ保証付きである
境界を守る.tcpはデータストリームに基づいているため、受信されたメッセージを空にすることはできません.これは、お客様が
エンドとサービスエンドは空のメッセージの処理メカニズムを追加し、プログラムの詰まりを防止し、udpはベースである.
データによると、あなたが空の内容を入力しても(直接車に戻る)、それはそうではありません.
空のメッセージ、udpプロトコルはメッセージヘッダをカプセル化します.
udpのrecvfromはブロックされており、1つのrecvfrom(x)は1つに対して1つでなければならない.
sendinto(y)は、xバイトのデータを受信して完了してもy>xのデータが失われ、
これはudpがパケットにくっつかないことを意味しますが、データが失われ、信頼できないtcpのプロトコルデータが失われず、パケットが受信されず、次回受信し、前回継続します.
受信すると、自己側は常にackを受信するとバッファの内容をクリアします.データは信頼できる
あ、でもべたべたします.
==============================================
FTP
client
import socket,optparse,json,os,shelve
class FtpClient:
'''Ftp '''
MSG_SIZE = 1024 # 1024
def __init__(self):
self.username=None
self.current_dir=None
self.terminal_display=None
self.shelve_obj=shelve.open('.luffy_db')
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 info")
parser.add_option("-p", "--password", dest="password", help="password info")
self.options,self.args=parser.parse_args()
print(self.options,self.args)
self.argv_verification()
self.make_connection()
def argv_verification(self):
''' IP PORT'''
if not self.options.server or not self.options.port:
exit('must supply server and port parameters')
def make_connection(self):
''' socket '''
self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.connect((self.options.server,self.options.port))
def get_response(self):
''' '''
data=self.sock.recv(self.MSG_SIZE)
return json.loads(data.decode())
def auth(self):
''' server'''
count=0
while count<3:
username=input('username: ').strip()
if not username:continue
password=input('password: ').strip()
cmd={
'action_type':'auth',
'username':username,
'password':password
}
self.sock.send(json.dumps(cmd).encode('utf8'))
response=self.get_response()
if response.get('status_code') == 200:
self.username=username
self.terminal_display=self.username
self.current_dir='\\'
return True
else:
print(response.get('status_msg'))
count+=1
def interactive(self):
''' '''
if self.auth():
self.unfinished_file_check()
while True:
user_input =input('[{}]>>: '.format(self.terminal_display)).strip()
if not user_input:continue
cmd_list=user_input.split()
if hasattr(self,'_{}'.format(cmd_list[0])):
func=getattr(self,'_{}'.format(cmd_list[0]))
func(cmd_list[1:])
def parameter_checke(self,args,min_args=None,max_args=None,exact_args=None):
''' '''
if min_args:
if len(args) < min_args:
print('must provide at least {} parameters but {} receivede'.format(min_args,len(args)))
return False
if max_args:
if len(args) > max_args:
print("need at most %s parameters but %s received." % (max_args, len(args)))
return False
if exact_args:
if len(args) != exact_args:
print("need exactly %s parameters but %s received." % (exact_args, len(args)))
return False
return True
def send_msg(self,action_type,**kwargs):
''' '''
msg_data={'action_type':action_type,
'fill':""}
msg_data.update(kwargs)
bytes_msg=json.dumps(msg_data).encode()
if len(bytes_msg) < self.MSG_SIZE:
msg_data['fill'].zfill(self.MSG_SIZE-len(bytes_msg))
bytes_msg = json.dumps(msg_data).encode()
self.sock.send(bytes_msg)
def get_response(self):
''' '''
data=self.sock.recv(self.MSG_SIZE)
return json.loads(data.decode('utf8'))
def unfinished_file_check(self):
''' shelve db
,
'''
if list(self.shelve_obj.keys()):
print("-------Unfinished file list -------------")
for index,abs_file in enumerate(self.shelve_obj.keys()):
received_file_size=os.path.getsize(self.shelve_obj[abs_file][1])
print("%s. %s %s %s %s" % (index, abs_file,
self.shelve_obj[abs_file][0],
received_file_size,
received_file_size / self.shelve_obj[abs_file][0] * 100
))
while True:
choice=input("[select file index to re-download]").strip()
if not choice:continue
if choice == 'back': break
if choice.isdigit():
choice=int(choice)
if choice >= 0 and choice <= index:
selected_file=list(self.shelve_obj.keys())[choice]
#self.shelve_obj[file_abs_path]=[file_size,'{}.dawnload'.format(filename)]
received_size = os.path.getsize(self.shelve_obj[selected_file][1])
self.send_msg('re_get',file_size=self.shelve_obj[selected_file][0],
received_size=received_size,
abs_filename=selected_file)
response=self.get_response()
if response.get('status_code') == 401:
local_file=self.shelve_obj[selected_file][1]
f=open(local_file,'ab')
total_size=self.shelve_obj[selected_file][0]
current_percent=int(received_size/total_size*100)
progess_generator=self.progrss_bar(total_size,current_percent=current_percent)
progess_generator.__next__()
while received_size > total_size:
if total_size-received_size<8192:
data=self.sock.recv(total_size-received_size)
else:
data=self.sock.recv()
f.write(data)
received_size+=len(data)
progess_generator.send(received_size)
else:
print("file re-get done")
f.close()
else:
print(response.get('status_code'))
def _get(self,cmd_args):
'''download file from server
1.
2.
3.
3.1 ,
3.1.1
3.2
print status_code
'''
if self.parameter_checke(cmd_args,min_args=1):
filename=cmd_args[0]
self.send_msg(filename=filename,action_type='get')
response=self.get_response()
if response.get('status_code') == 301:#
file_size=response.get('file_size')
received_size=0
progress_generator = self.progress_bar(file_size)#
progress_generator.__next__()
file_abs_path=os.path.join(self.current_dir,filename)
self.shelve_obj[file_abs_path]=[file_size,'{}.dawnload'.format(filename)]
f=open('{}.dawnload'.format(filename),'wb')
while received_size < file_size:
if file_size-received_size<8192:
data=self.sock.recv(file_size-received_size)
else:
data=self.sock.recv(8192)
f.write(data)
progress_generator.send(received_size)
else:
print("---file [%s] recv done,received size [%s]----" % (filename, file_size))
del self.shelve_obj[file_abs_path]
f.close()
os.rename('{}.dawnload'.format(filename),filename)
else:
print(response.get('status_msg'))
def _ls(self,data):
'''
, '''
self.send_msg(action_type='ls')
response=self.get_response()
if response.get('status_code') == 302:# long
cmd_result_size=response.get('cmd_result_size')
received_size=0
cmd_result=b''
while received_size < cmd_result_size:
if cmd_result_size -received_size<8192:
data=self.sock.recv(cmd_result_size -received_size)
else:
data=self.sock.recv(8192)
received_size+=len(data)
cmd_result+=data
else:
print(cmd_result.decode('GBK'))
def _cd(self,args):
'''
'''
if self.parameter_checke(args,exact_args=1):
target_dir=args[0]
self.send_msg(action_type='cd',target_dir=target_dir)
response=self.get_response()
if response.get['status_code']== 350:
self.terminal_display=response.get['current_dir']
self.current_dir=response.get['current_dir']
def progrss_bar(self,total_size,current_percent=0,last_percent=0):
''' '''
while True:
received_size=yield
current_percent=int(received_size/total_size*100)
if current_percent >last_percent:
print('#'*(int(current_percent)/2) +'[{}]'.format(current_percent),end='\r')
last_percent=current_percent
def _put(self,data):
'''
1.
2.
3.
:param data:
:return:
'''
if self.parameter_checke(data,exact_args=1):
local_file=data[0]
if os.path.isfile(local_file):
total_size=os.path.getsize(local_file)
self.send_msg('put',file_size=total_size,filename=local_file)
f=open(local_file,'rb')
progrss_generator=self.progrss_bar(total_size)
progrss_generator.__next__
uploaded_size=0
for line in f:
self.sock.send(line)
uploaded_size+=0
progrss_generator.send(uploaded_size)
else:
print()
print('uploaded file done...'.center(50,'-'))
f.close()
def _pwd(self,args):
'''
:return:
'''
print('{}'.format(self.current_dir))
def _mkdir(self,args):
'''
1.
2.
:param args:
:return:
'''
if self.parameter_checke(args, exact_args=1):
new_dir = args[0]
print(new_dir)
self.send_msg(action_type='mkdir', new_dir=new_dir)
response = self.get_response()
if response.get('status_code') == 353:
cmd_result_size = response.get('cmd_result_size')
received_size = 0
cmd_result = b''
while received_size < cmd_result_size:
if cmd_result_size - received_size < 8192: # last receive
data = self.sock.recv(cmd_result_size - received_size)
else:
data = self.sock.recv(8192)
cmd_result += data
received_size += len(data)
else:
print(cmd_result.decode("gbk"))
if response.get('status_code') == 352:
print('Dir create success')
def _del(self,args):
'''
,
'''
if self.parameter_checke(args,min_args=1):
filename=args[0]
self.send_msg(filename=filename,action_type='del')
response=self.get_response()
if response.get('status_code')== 500:
print('delect success')
if response.get('status_code')== 501:
print("NO search file or dir")
else:
data=self.sock.recv(8192)
print(data.decode('GBK'))
if __name__ =='__main__':
client=FtpClient()
client.interactive()
server import sys,os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
if __name__ == '__main__':
from core import management
argv_parser=management.ManagementTool(sys.argv)
argv_parser.execute()#
from core import main
class ManagementTool:
''' '''
def __init__(self,sys_argv):
self.sys_argv=sys_argv# sys.argv [' ','']
print(self.sys_argv)
self.verify_argv()# sys_argv
def verify_argv(self):
''' '''
if len(self.sys_argv) < 2:# sys.argv ,
self.help_msg()
cmd=self.sys_argv[1]
if not hasattr(self,cmd):#
print('invalid argument')
self.help_msg()
def help_msg(self):
msg='''
start start FTP server
stop stop FTP server
restart testart FTP server
createuser username create a ftp user
'''
exit(msg)#
def execute(self):
''' '''
cmd=self.sys_argv[1]
func=getattr(self,cmd)#
func()
def start(self):
''' '''
server=main.FTPServer(self)
server.run_forever()
import socket,json,configparser,hashlib,os,subprocess,time
from conf import settings
class FTPServer:
''' '''
STATUS_CODE = {
200: "Passed authentication!",
201: "Wrong username or password!",
300: "File does not exist !",
301: "File exist , and this msg include the file size- !",
302: "This msg include the msg size!",
350: "Dir changed !",
351: "Dir doesn't exist !",
352: "Dir create success",
353:"Dir does exist",
401: "File exist ,ready to re-send !",
402: "File exist ,but file size doesn't match!",
500: 'delect success',
501: "Dir or file doesn't exist !"
}
MSG_SIZE = 1024 # 1024
def __init__(self,management_instence):
self.management_instence=management_instence
self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.bind((settings.HOST,settings.PORT))
self.sock.listen(5)
self.accounts=self.load_accounts()
self.user_obj=None
self.user_current_dir=None
def run_forever(self):
''' , '''
print('starting FTP server on {},{}'.center(50,'-').format(settings.HOST,settings.PORT))
while True:
self.request,self.addr=self.sock.accept()
print('got a new connection form {}....'.format(self.addr,))
self.handle()
def handle(self):
''' '''
while True:
raw_data=self.request.recv(self.MSG_SIZE)
if not raw_data:
print('connection {} is lost...'.format(self.addr))
del self.request,self.sock
break
data=json.loads(raw_data.decode('utf8'))# ,
action_type=data.get('action_type')# action_type
if action_type:#
if hasattr(self,'_{}'.format(action_type)):
func=getattr(self,'_{}'.format(action_type))
func(data)
else:
print('invalid command')
def load_accounts(self):
''' '''
config_obj=configparser.ConfigParser()
config_obj.read(settings.ACCOUNTS_FILE)#
return config_obj
def authenticate(self,username,password):
''' '''
if username in self.accounts:
_password = self.accounts[username]['password']
md5_obj=hashlib.md5()
md5_obj.update(password.encode())
if _password == md5_obj.hexdigest():
self.user_obj=self.accounts[username]#
self.user_obj['home']=os.path.join(settings.USER_HOME_DIR,username)
self.user_current_dir=self.user_obj['home']
#
return True
else:
return False
else:
return False
def send_response(self,status_code,*args,**kwargs):
'''
:param status_code:200
:param args:
:param kwargs:{'filename':filename,'size':filesize}
:return
'''
data=kwargs# ,
data['status_code']=status_code
data['status_msg']=self.STATUS_CODE[status_code]
data['fill']=''
bytes_data=bytes(json.dumps(data).encode())
if len(bytes_data) < self.MSG_SIZE:
data['fill'].zfill(self.MSG_SIZE-len(bytes_data))
bytes_data = bytes(json.dumps(data).encode())
self.request.send(bytes_data)
def _auth(self,data):
''' '''
if self.authenticate(data.get('username'),data.get('password')):
print('pass auth...')
self.send_response(status_code=200)
else:
self.send_response(status_code=201)
def _get(self,data):
'''
1.
2.
2.1 ,
2.1.1
2.2 ,
:return:
'''
filename=data.get('filename')
full_path=os.path.join(self.user_obj['home'],filename)#
if os.path.isfile(full_path):
filesize=os.stat(full_path).st_size
self.send_response(status_code=301,file_size=filesize)
print('ready to send file')
f=open(filename,'rb')
for line in f:
self.request.send(line)
else:
print('file send done..',full_path)
f.close()
else:
self.send_response(status_code=300)#
def _ls(self,data):
''' dir client'''
print(self.user_current_dir)
cmd_obj=subprocess.Popen('dir {}'.format(self.user_current_dir),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout=cmd_obj.stdout.read()
stderr=cmd_obj.stderr.read()
cmd_result=stdout+stderr
if not cmd_result:
cmd_result=b'current dir has not file at all'
self.send_response(status_code=302,cmd_result_size=len(cmd_result))
self.request.sendall(cmd_result)
def _cd(self,data):
'''
1. target_dir user_current_dir
2. target_dir
2.1 user_current_dir
2.2
'''
target_dir=data.get('target_dir')
full_dir=os.path.abspath(os.path.join(self.user_current_dir,target_dir))
#abspath cd .. c:\a\b\c\..\..=c:\a
if os.path.isdir(full_dir):
if full_dir.startswith(self.user_obj['home']):
self.user_current_dir=full_dir
relative_current_dir=full_dir.replace(self.user_obj['home'],'')
self.send_response(status_code=350,current_dir=relative_current_dir)
else:
self.send_response(status_code=351)
else:
self.send_response(status_code=351)
def _put(self,data):
'''
1.
2.
2.1 ,
2.1
2.2 ,
:param data:
:return:
'''
local_file=data.get('filename')
full_path=os.path.join(self.user_current_dir,local_file)
if os.path.isfile(full_path):
filename='{}.{}'.format(full_path,time.time())
else:
filename=full_path
f=open(filename,'wb')
received_size=0
total_size=data.get('tatal_size')
while received_size < total_size:
if total_size-received_size <8192:
data=self.request.recv(total_size-received_size)
else:
data=self.request.recv(8192)
received_size+=len(data)
f.write(data)
else:
print('file %s recv done'% local_file)
f.close()
def _re_get(self,args):
'''
1. ,
2.
2.1 ,
2.1.1 ,
2.1.1.1 ,sock
2.1.2 ,
2.2
:param args:
:return:
'''
abs_filename=args.get('abs_filename')
full_path=os.path.join(self.user_obj['home'],abs_filename.strip('\\'))
if os.path.isfile(full_path):
if os.path.getsize(full_path)== args.get('file_size'):
self.send_response(status_code=401)
f=open(full_path,'rb')
f.seek(args.get('received_size'))
for line in f:
self.request.recv(line)
else:
print("-----file re-send done------")
f.close()
else:
self.send_response(status_code=402,file_size_on_server=os.path.getsize(full_path))
else:
self.send_response(status_code=300)
def _mkdir(self,argv):
'''
1.
2. mkdir
3.
:param argv:
:return:
'''
new_dir=argv.get('new_dir')
create_target_dir=os.path.join(self.user_current_dir,new_dir)
cmd_obj = subprocess.Popen('mkdir {}'.format(create_target_dir), shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = cmd_obj.stdout.read()
stderr = cmd_obj.stderr.read()
cmd_result = stdout + stderr
if len(cmd_result)==0:
self.send_response(status_code=352)
else:
self.send_response(status_code=353,cmd_result_size=len(cmd_result))
self.request.sendall(cmd_result)
def _del(self,args):
'''
1.
2.
2.1 del
2.2 DIR rd
3.
:param args:
:return:
'''
filename=args.get('filename')
file_path=os.path.join(self.user_current_dir,filename)
if os.path.isfile(file_path):
s = subprocess.Popen('del {}'.format(file_path), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
f1 = s.stdout.read()
f2 = s.stderr.read()
f = f1 + f2
if not f:
self.send_response(status_code=500)
else:
self.request.sendall(f)
elif os.path.isdir(file_path):
s = subprocess.Popen('rd {}'.format(file_path), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
f1 = s.stdout.read()
f2 = s.stderr.read()
f = f1 + f2
if not f:
self.send_response(status_code=500)
else:
self.request.sendall(f)
else:
self.send_response(status_code=501)