進程和線程的區別和聯系:
1.兩者都是多任務編程方式,都能夠使用計算機的多核
2.進程的創建和刪除消耗的計算機資源比線程要多
3.進程空間獨立,數據互不干擾,有專門的通信方法,而線程使用全局變量進行通信
4.一個進程可以創建多個線程分支,兩者之間存在包含關系
5.多個線程公用進程資源,在共享資源操作時往往需要同步互斥操作
6.進程線程都在系統中有自己的特有屬性標志,如ID,代碼段,命令集等
使用場景:
* 某個任務中並發比較多,此時多線程消耗資源較少
* 不同的獨立的任務模塊,用多線程相對空間比較好管理
* 在通信上考慮可行性如果數據邏輯復雜需要的同步互斥較多,這時使用線程同步互斥可能容易出錯
要求:
1.進程線程的區別
2.進程間通信都知道哪些?有什么特點
3.什么是同步互斥,你在什么情況下使用
4.給一個情形,分析用進程還是線程為什么?
5.問一些概念和處理方法,僵屍進程,進程狀態,線程效率
網絡通信模型
服務器:
軟件服務器:編寫的服務器端應用程序,在硬件服務器上運行,提供一定的完整的后端服務
硬件服務器:主機 集群
httpsever------> 處理http請求
websever--------> 網站的后端服務程序
郵箱服務器-------> 郵件處理
ftp服務器------>文件處理
前端 用戶端 客戶端 前台應用
特征:與用戶直接交互,提供給用戶使用
要求:良好的用戶體驗
后端 服務端 后台應用
特征:提供邏輯處理,數據處理
要求:更高的並發量,更快的處理速度,更強的安全性
服務器模型
服務器的基本結構: c/s 客戶端服務器模型
b/s 瀏覽器服務器模型
網絡通信模型
循環服務器模型:循環接收客戶端請求,處理請求,同一時刻只能處理一個請求,處理完畢后在處理下一個
優點:實現簡單,占用資源少
缺點:無法同時處理多個客戶端請求
適用情況:處理的任務可以很快完成,不需要建立並發,udp比tcp更適合循環模型
並發服務器模型:能夠同時處理多個客戶端的請求
IO並發:io 多路復用
優點:資源消耗少,能同時處理多個io
缺點:只能監控io事件,當多個任務都是cpu計算時無法同時處理
多進程多線程並發:為每個客戶端創建單獨的進程或者線程處理客戶端請求
優點:每個客戶端都可以長期占有服務器,能使用多核資源處理IO或者cpu計算
缺點:資源消耗較高
多進程並發
基於fork完成多進程網絡並發
1.創建套接字,綁定,監聽
2.等待接收客戶端連接請求 accept
3.當有新的客戶端連接時,創建新的進程處理客戶端請求
4.原有進程繼續等待其他客戶端連接,新的進程處理客戶端具體請求
5.如果客戶端退出,則銷毀對應的進程
ftp 文件服務器
功能:1.服務器和客戶端兩部分,要求啟動服務器后可以有多個客戶端同時操作
2.客戶端可以查看服務器文件庫中有什么文件(只有普通文件,不算隱藏文件)
3.客戶端可以選擇文件庫中的文件進行下載,下載到本地
4.客戶端還可以上傳本地文件到服務器文件夾(不設權限)
5.使用print打印一定的格式,作為命令的輸入界面提示
技術分析: fork()並發,tcp傳輸,如何查看一個文件夾中的文件列表(os.listdir)
如何判斷是一個普通文件(os.path.isfile)
結構設計:使用類將功能封裝
工作步驟:先搭建網絡連接
設計類
將功能函數寫在類中,逐一實現並測試
具體功能: 1.搭建網絡連接
服務端:創建fork並發服務端程序
客戶端:創建套接字,進行網絡連接,連接成功后打印
命令選項界面等待輸入命令
2.設計類
3.查看文件列表
客戶端:發送請求
接收服務端確認
循環接收服務器發來的文件名並打印
服務端:接收請求
判斷可否執行反饋結果
發送文件名稱
4.下載文件
客戶端:發送請求:G filename
接收服務端確認
接收文件
服務端:接收請求
判斷文件是否存在,反饋結果
發送文件
多線程並發
基於threading模塊
1.創建套接字,綁定監聽
2.接收客戶端請求
3.創建新的線程處理客戶端請求
4.主線程繼續等待其他客戶端連接,分支線程處理其他具體請求
5.當客戶端退出則線程退出
'''
FTP文件傳輸服務器
流式套接字
'''
from socket import *
import time,sys,os
HOST = '0.0.0.0'
PORT = 2505
ADDR = (HOST,PORT)
FILE_PATH ='/home/tarena/aid1808/linux/pythonnet/day08/ftp/'
class FtpServer():
def __init__(self,c):
self.c = c
def do_list(self):
# 如果文件列表為空則不能執行
file_list = os.listdir(FILE_PATH)
if not file_list:
self.c.send("文件夾為空".encode())
return
else:
self.c.send(b'OK')
time.sleep(0.1)
files = ''
for file in file_list:
if file[0] != '.' and os.path.isfile(FILE_PATH + file):
files += file +'#'
# 將拼接好的文件列表字符串發送給客戶端
self.c.sendall(files.encode())
def do_get(self,filename):
try:
f = open(FILE_PATH+filename,'rb')
except:
f.close()
self.c.send("文件不存在".encode())
return
else:
self.c.send("OK".encode())
time.sleep(0.1)
while True:
data = f.read(1024)
if not data:
time.sleep(0.1)
self.c.send(b'##')
break
self.c.send(data)
f.close()
def do_put(self,filename):
# print("wait")
try:
f = open(FILE_PATH+filename,'wb')
# print("open")
except:
self.c.send("文件上傳服務器失敗".encode())
f.close()
return
else:
self.c.send(b"OK")
time.sleep(0.1)
while True:
# print("***")
data = self.c.recv(1024)
if data == b"##":
break
f.write(data)
f.close()
print("接收完畢")
def main():
#創建套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
s.listen(5)
print("wait for connect...")
while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
s.close()
sys.exit("服務器退出")
except Exception as err:
print('Error',err)
continue
print("連接到客戶端",addr)
#創建子進程,子進程去處理客戶端請求,主進程繼續等待其他客戶端的連接
pid = os.fork()
if pid == 0:
# 創建二級子進程,一級子進程退出,主進程回收一級子進程,二級子進程執行請求,防止僵屍進程
p = os.fork()
if p == 0:
s.close() #防止子進程擁有主進程全部代碼,誤操作
#在二級子進程中,先將收到的請求分類,將處理的請求在類中封裝處理..
# 創建對象
ftp = FtpServer(c)
# 循環接收用戶的請求
while True:
data = c.recv(1024).decode()
if not data or data[0].strip().upper()=='Q':
c.close()
sys.exit("客戶端退出")
elif 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)
else:
os._exit(0) # 創建二級子進程失敗后,程序跳出循環,重新等待連接
else:
c.close()
os.wait() #因為一級子程序很快就會結束,所以主進程回收一級子進程
continue
# 測試代碼
if __name__=='__main__':
main()
'''
FTP文件傳輸客戶端
'''
from socket import *
import time
import sys
class FtpClient():
def __init__(self,s):
self.s = s
def do_list(self):
self.s.send(b'L')
data = self.s.recv(128).decode()
if data == 'OK':
files = self.s.recv(4096).decode()
file_list = files.split('#')
for file in file_list:
print(file,end=' ')
print()
print("文件展示完畢")
else:
print(data)
def do_quit(self):
self.s.send(b'Q')
self.s.close()
sys.exit('謝謝使用')
def do_get(self,filename):
self.s.send(('G ' + filename).encode())
data = self.s.recv(128).decode()
if data == "OK":
try:
f = open(filename,'wb')
except:
print("打開文件失敗")
return
else:
while True:
data1 = self.s.recv(1024)
if data1 == b'##':
break
f.write(data1)
f.close()
print('%s下載完畢'%filename)
else:
print(data)
def do_put(self,filename):
try:
f = open(filename,'rb')
# print("open")
except:
print("上傳文件失敗")
f.close()
return
self.s.send(('P '+filename).encode())
data = self.s.recv(128).decode()
if data == "OK":
while True:
data1 = f.read(1024)
if not data1:
time.sleep(0.1)
self.s.send(b'##')
break
self.s.send(data1)
f.close()
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)
# 創建套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
try:
s.connect(ADDR)
except Exception as err:
print("連接服務器失敗",err)
return
# 創建對象
ftp = FtpClient(s)
while True:
print('============命令選項============')
print('1)****** list ******')
print('2)****** get file ******')
print('3)****** put file ******')
print('4)****** quit ******')
#用戶輸入選擇
cmd = input(">>>")
if cmd.strip() == 'list':
ftp.do_list()
elif cmd.strip() == 'quit':
ftp.do_quit()
elif cmd[:3] == 'get':
filename = cmd.split(' ')[-1]
ftp.do_get(filename)
elif cmd[:3] == "put":
filename = cmd.split(' ')[-1]
ftp.do_put(filename)
else:
print("請重新輸入命令")
# 測試代碼
if __name__=='__main__':
main()
from socket import *
import os,sys
def client_handler(c):
print('客戶端:',c.getpeername())
while True:
data = c.recv(1024)
if not data:
break
print(data.decode())
c.send(b'Receive your message')
c.close()
sys.exit(0) #將子進程銷毀
#創建套接字
HOST = '0.0.0.0'
PORT = 2505
ADDR = (HOST,PORT)
s = socket() #tcp套接字
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
s.listen(5)
#循環等待客戶端連接
print('Listen to the port 2505....')
while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
sys.exit("退出服務器")
except Exception as e:
print('Error:',e)
continue
#創建新的進程處理客戶端請求
pid = os.fork()
#子進程處理客戶端請求
if pid == 0:
p = os.fork()
if p==0:
s.close()
client_handler(c) #客戶端處理函數
else:
os._exit(0)
# 父進程或者創建進程失敗都繼續等待下個客戶端連接
else:
c.close()
os.wait()
continue
'''
基於Process多進程服務器
'''
from multiprocessing import *
from socket import *
import sys
HOST = '0.0.0.0'
PORT = 2505
ADDR = (HOST,PORT)
def handler():
print('Connect from ',c.getpeername())
while True:
data = c.recv(1024)
if not data:
break
print(data.decode())
c.send(b'Receive')
c.close()
sys.exit(0)
# 創建套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
s.listen(5)
# 接收客戶端請求
while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
s.close()
sys.exit('服務器退出')
except Exception as err:
print(err)
continue
# 創建新的線程
t = Process(target = handler)
t.daemon=True
t.start()