NO.8:自学python之路------并行socket网络编程
摘要
一到放假就雜事很多,這次的作業(yè)比較復(fù)雜,做了一個(gè)周,進(jìn)度又拖了。不過(guò)結(jié)果還不錯(cuò)。
正文
粘包
在上一節(jié)中,如果連續(xù)發(fā)送過(guò)多數(shù)據(jù),就可能發(fā)生粘包。粘包就是兩次發(fā)送的數(shù)據(jù)粘在一起被接收,損壞了數(shù)據(jù)的完整性。解決方法有兩種。
方案一:
在發(fā)送多個(gè)數(shù)據(jù)之間添加接收確認(rèn)。這樣在完成一次發(fā)送以后只有接收到另一端的確認(rèn)以后才會(huì)開(kāi)始新的發(fā)送,避免了粘包的發(fā)生。
方案二:
首先將發(fā)送數(shù)據(jù)的大小發(fā)送給另一端,另一端根據(jù)數(shù)據(jù)的大小接收。一次接收一次發(fā)送的數(shù)據(jù)量,這樣也就避免了數(shù)據(jù)的粘包。例子。
#方案1 #server f = open(path, 'wb') for i in f:server.socket.send(i) f.close() server.socket.recv(1024) server.socket.send(b'發(fā)送完畢') #client recv_data = '' while True:data = client.socket.recv(1024)if not data:breakrecv_data += data client.socket.send(b'recv over') other_data = client.socket.recv(1024) #方案2 #server size = os.path.getsize(path) server.socket.send(size.encode()) server.socket.recv(1024) f = open(path, 'wb') for i in f:server.socket.send(i) f.close() server.socket.send(b'發(fā)送完畢') #client size = client.socket.recv(1024) client.socket.send(b'start') recv_data = '' recv_size = 0 while recv_size < size:if size - recv_size < 1024:single_size = size - recv_sizeelse:single_size = 1024data = client.socket.recv(single_size)recv_size += len(data)recv_data += data other_data = client.socket.recv(1024) View CodeFTP
一個(gè)簡(jiǎn)單的FTP過(guò)程主要包含以下幾個(gè)步驟。
1.讀取文件名
2.檢測(cè)文件是否存在
3.打開(kāi)文件
4.檢測(cè)文件大小,文件名
5.發(fā)送文件大小 md5值給客戶端
6.等待客戶端確認(rèn)
7.開(kāi)始邊讀取數(shù)據(jù)邊發(fā)送數(shù)據(jù)
8.md5確認(rèn)
具體例子。
服務(wù)器
# 服務(wù)器端 import socket import os import hashlibserver = socket.socket() server.bind(('localhost', 9999)) server.listen()while True:conn, addr = server.accept()print('new conn:', addr)while True:data = conn.recv(1024)data = data.decode()if not data:print('客戶端已斷開(kāi)')breakcmd, filename = data.split()print(filename)if os.path.isfile(filename):f = open(filename, 'rb')m = hashlib.md5()file_size = os.stat(filename).st_sizeprint(file_size)conn.send(str(file_size).encode('utf-8'))conn.recv(1024)for line in f:m.update(line)conn.send(line)print('md5:', m.hexdigest())f.close()conn.send(m.hexdigest().encode('utf-8')) View Code客戶端
# 客戶端 import socket import hashlibclient = socket.socket() client.connect(('localhost', 9999))while True:cmd = input('>>').strip()if len(cmd) == 0:continueif cmd.startswith('get'):client.send(cmd.encode('utf-8'))cmd_res_size = client.recv(1024) # 接收長(zhǎng)度print('文件大小 %s' % (cmd_res_size.decode()))client.send('準(zhǔn)備完畢,開(kāi)始發(fā)送數(shù)據(jù)'.encode('utf-8'))recv_size = 0file_name = cmd.split()[1]f = open(file_name + '.new', 'wb')m = hashlib.md5()while recv_size < int(cmd_res_size.decode()):if int(cmd_res_size.decode()) - recv_size > 1024:size = 1024else:size = int(cmd_res_size.decode()) - recv_sizedata = client.recv(size)recv_size += len(data) # 讀取每次接收的數(shù)據(jù) f.write(data)m.update(data)#print(recv_size)else:file_md5 = m.hexdigest()print('文件接收完畢', recv_size)f.close()recv_md5 = client.recv(1024)print(file_md5, recv_md5.decode()) client.close() View CodeSocketServer
SocketServer是Python的一個(gè)包,它在socket的基礎(chǔ)上封裝,可以更加簡(jiǎn)單的完成并發(fā)處理。
socketserver.TCPServer 繼承BaseServer,完成TCP
socketserver.UDPServer 繼承TCPServer,完成UDP
socketserver.UnixStreamServer?繼承TCPServer,完成Unix的TCP
socketserver.UnixDatagramServer?繼承UDPServer,完成Unix的UDP
使用socketserver的步驟:
1.創(chuàng)建一個(gè)請(qǐng)求處理類(lèi),并且這個(gè)類(lèi)要繼承BaseRequestHandler,并且需要重寫(xiě)父類(lèi)中的Handle()方法。
2.實(shí)例化一個(gè)Server類(lèi),并且傳遞Server ip和1中創(chuàng)建的請(qǐng)求處理類(lèi)給它。
3.server.handle_request()只處理一個(gè)請(qǐng)求 server.server_forever()處理多個(gè)請(qǐng)求,永久執(zhí)行。
4.調(diào)用server_close()關(guān)閉它。
BaseServer中的常用方法,例子。
fileno() # 返回文件描述符 handle_request # 處理單個(gè)請(qǐng)求 serve_forever(poll_interval=0.5) # 一直運(yùn)行直到收到shutdown()請(qǐng)求,每poll_interval檢查一次,后調(diào)用service_actions()結(jié)束 service_actions() # 結(jié)束操作 shutdown() # 停止信號(hào) server_close() # 清除server address_family # 地址簇 RequestHandlerClass # 請(qǐng)求處理類(lèi) server_address # ip地址 socket # 同socket self.allow_reuse_adress # 允許重用地址 socket中socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) socket_type # socket使用的協(xié)議類(lèi)型 self.setup() # 請(qǐng)求來(lái)之前 self.handle() # 請(qǐng)求來(lái)時(shí) self.finish() # 請(qǐng)求處理之后 View Code作業(yè)
1.用戶加密認(rèn)證
2.允許多個(gè)用戶登陸
3.每個(gè)用戶有自己的家目錄,不能互相訪問(wèn)
4.對(duì)用戶進(jìn)行磁盤(pán)配額,可用空間不同
5.允許用戶在ftp_server上隨意切換目錄
6.允許用戶查看當(dāng)前目錄文件
7.允許用戶上傳下載文件,保證文件一致性
8.傳輸過(guò)程顯示進(jìn)度條
作業(yè)
轉(zhuǎn)載于:https://www.cnblogs.com/zk71124720/p/9407286.html
總結(jié)
以上是生活随笔為你收集整理的NO.8:自学python之路------并行socket网络编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: Assigned 的迷思
- 下一篇: Vue项目引入字体(思源黑体)
