socket只能實現同時一個服務和一個客戶端實現交互,socketserver可以實現多個客戶端同時和服務端交互
1.利用Socket編寫簡單的同一個端口容許多次會話的小案例:
服務端:
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:CarsonLi
import socket
'''模擬服務端'''
server=socket.socket()
server.bind(('localhost',6969)) #綁定需要監聽的端口
server.listen(5) #開始監聽
print('開始等待客戶端發起請求')
while True:
conn,addr=server.accept() #等待客戶端連接,並且返回兩個參數
#conn是客戶端連接過來而在服務器為期生成的一個連接實例, addr為連接的地址
print('服務器為客戶端連接生成的實例:',conn)
print('客戶端連接地址:',addr)
while True:
data=conn.recv(1024) #接收客戶端發來的信息
print(data.decode())
conn.send(data.upper()) #返回個客戶端信息
server.close()
客戶端:
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:CarsonLi
import socket
'''模擬客戶端'''
client=socket.socket() #聲明socket類型,同時創建socket連接對象
client.connect(('localhost',6969))
while True:
msg=input('請輸入需要發送的內容>>:').strip()
if len(msg)==0: #輸入信息為空時不發送,否則在linux下運行時會出現死循環
continue
else:
client.send(msg.encode("utf-8")) #發送信息 在python3以后都只能發送byte類型,
data=client.recv(1024)#接收到的信息,需要定義大小
print(data.decode())
client.close()
服務端運行結果:
D:\Python3.7.0\python.exe D:/PycharmProjects/OldManS14/day07/socket_server.py
開始等待客戶端發起請求
服務器為客戶端連接生成的實例: <socket.socket fd=436, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6969), raddr=('127.0.0.1', 64403)>
客戶端連接地址: ('127.0.0.1', 64403)
第一次
第二次
第三次
第四次
第五次
客戶端運行結果:
D:\Python3.7.0\python.exe D:/PycharmProjects/OldManS14/day07/socket_client.py 請輸入需要發送的內容>>:第一次 第一次 請輸入需要發送的內容>>:第二次 第二次 請輸入需要發送的內容>>:第三次 第三次 請輸入需要發送的內容>>:第四次 第四次 請輸入需要發送的內容>>:第五次 第五次 請輸入需要發送的內容>>:
2.SocketServer 支持多個客戶端
'''
SocketServer 支持多個客戶端
'''
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
'''
處理我們的socket,這個類必須繼承socketserver.BaseRequestHandler
並且實現里面的handler函數
'''
def setup(self):
print("這里處理請求前的的事情,也可以不寫")
pass
def handle(self):
'''處理客戶端請求'''
while self:
try:
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))#客戶端地址
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:
print("客戶端斷開", e)
break
def finish(self):
print("處理請求完成之后的事情,也可以不寫")
pass
if __name__=="__main__":
HOST,PORT = "localhost",6969
# server = socketserver.TCPServer((HOST,PORT),MyTCPHandler #不支持多並發
server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) #支持多線程,多並發
# server = socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler) # 支持多進程,多並發,windows不能實現,linux上可以
#server.allow_reuse_address() #解決 在 socketServer程序里面出現 地址已經被占用
server.serve_forever()
3.模擬ftp上傳下載(只實現了里面的上傳功能,其他功能也大同小異,就沒有一一去寫)
import socketserver,os,json
'''模擬ftp上傳下載的服務端'''
class MyTCPHandler(socketserver.BaseRequestHandler):
def setup(self):
pass
def handle(self):
while True:
try:
self.data = self.request.recv(1024).strip()
print("{}".format(self.client_address[0]))
msg_dic = json.loads(self.data.decode())
print(msg_dic)
if hasattr(self,"server_"+msg_dic.get("action")):
func = getattr(self,"server_"+msg_dic.get("action"))
func(msg_dic)
except ConnectionResetError as e:
print(e)
break
def server_put(self,*args):
'''服務端文件上傳操作'''
msg_dic = args[0]
file_name = msg_dic.get("file_name") #文件名稱
file_size = msg_dic.get("file_size")#文件大小
if os.path.isfile(file_name):
files = file_name.split(".") #截取文件名添加new ,例如 file.txt ==> file_new.txt
f = open(files[0]+"_new."+files[1],"wb")
else:
f = open(file_name, "wb")
self.request.send(b"200 ok")
recv_file_size = 0
while recv_file_size < file_size:
recv_data = self.request.recv(1024)
f.write(recv_data)
recv_file_size += len(recv_data) #大小計算
else:
print("file [%s] has uploaded..." % file_name)
f.close()
def server_get(self,*args):
''' 下載文件功能 '''
pass
def server_del(self,*args):
''' 下載刪除功能 '''
pass
if __name__ == "__main__":
ip,port = "localhost",9999
server = socketserver.ThreadingTCPServer((ip,port),MyTCPHandler)
server.serve_forever()
客戶端:
import socket,os,json
'''模擬ftp上傳下載的客戶端'''
class MyTCPClient(object):
def __init__(self):
self.client=socket.socket()
def help(self):
pass
def connection(self,ip,port):
'''連接服務器'''
self.client.connect((ip, port))
def interactive(self):
while True:
input_str = input(">>:").strip()
if len(input_str) == 0: continue
action = input_str.split()[0]
if hasattr(self,"cmd_"+action): #用反射判斷是否存在
func = getattr(self,"cmd_"+action)
func(input_str)
else:
print(action,"is not exist!")
def client_put(self,*args):
'''客戶端文件上傳操作'''
input_str = args[0]
input_split = input_str.split()
if os.path.isfile(input_split[1]): # 判斷是否是文件
file_size = os.stat(input_split[1]).st_size
msg_dic = {
"action":input_split[0],
"file_name":input_split[1],
"file_size":file_size
}
self.client.send(json.dumps(msg_dic).encode("utf-8")) #序列化之后編碼
server_respone = self.client.recv(1024) #等待客戶端確認
f = open(input_split[1],"rb") #打開文件
for line in f:
self.client.send(line)
else:
print(input_split[1],"upload success!")
f.close() #關閉文件
else:
print(input_split[1], "is not exist!")
def client_get(self,*args):
'''文件下載操作'''
pass
def client_del(self,*args):
'''刪除功能'''
pass
if __name__ == "__main__":
tcp_client = MyTCPClient()
tcp_client.connection("localhost",9999)
tcp_client.interactive()
