Python中的Socket 與 ScoketServer 通信及遇到問(wèn)題解決方法
Socket有一個(gè)緩沖區(qū),緩沖區(qū)是一個(gè)流,先進(jìn)先出,發(fā)送和取出的可自定義大小的,如果取出的數(shù)據(jù)未取完緩沖區(qū),則可能存在數(shù)據(jù)怠慢。其中【recv(1024)】表示從緩沖區(qū)里取最大為1024個(gè)字節(jié),但實(shí)際取值大小是不確定的,推薦其值小于等于8192。
黏包問(wèn)題:
Socket發(fā)送兩條連續(xù)數(shù)據(jù)時(shí),可能最終會(huì)拼接成一條進(jìn)行發(fā)送
解決方法一:
兩條數(shù)據(jù)間進(jìn)行延時(shí)發(fā)送,如【tiem.sleep(0.5) #延時(shí)0.5s】
解決方法二:
每次發(fā)送后等待對(duì)方確認(rèn)接收信息數(shù)據(jù),發(fā)送一條后就立即接收等待
解決方法三:
設(shè)定接收數(shù)據(jù)大小,發(fā)送端每次發(fā)送需要發(fā)送的數(shù)據(jù)的數(shù)據(jù)大小,接收端通過(guò)設(shè)置【recv(xx)】只接收確定的大小
Socket基本使用:
簡(jiǎn)單的服務(wù)器:
import socket
sser=socket.socket()#得到socket對(duì)象
sser.bind(("0.0.0.0",2699))#建立監(jiān)聽(tīng)
sser.listen(3)
print("等等客戶端連接")
conn,addr=sser.accept() #等待連接,會(huì)一直處于阻塞,返回連接對(duì)象和對(duì)方地址
print("有客戶端已經(jīng)連接,IP地址和端口為:",addr)
#接收數(shù)據(jù),會(huì)一直阻塞,建議低于8192
#使用連接對(duì)象操作
rdata=conn.recv(1024)
print(rdata.decode("gbk"))
conn.send("服務(wù)器返回,收到數(shù)據(jù)".encode("gbk"))#發(fā)送數(shù)據(jù),使用連接對(duì)象操作
#關(guān)閉連接
sser.close()
簡(jiǎn)單的客戶端:
import socket
sclient=socket.socket()#得到socket對(duì)象
#連接服務(wù)器
#失敗會(huì)報(bào)錯(cuò):ConnectionRefusedError
sclient.connect(("192.168.1.135",2699))
sclient.send("東小東".encode("gbk"))#發(fā)送數(shù)據(jù)
#接收數(shù)據(jù),會(huì)一直阻塞,建議低于8192
rdata=sclient.recv(1024)
print(rdata.decode("gbk"))
#關(guān)閉連接
sclient.close()
Soket進(jìn)階:
服務(wù)器進(jìn)階:
實(shí)現(xiàn)客戶循環(huán)連接及數(shù)據(jù)循環(huán)收發(fā)和判斷客戶端是否斷開
import socket
sser=socket.socket()#得到socket對(duì)象
sser.bind(("0.0.0.0",2699))#建立監(jiān)聽(tīng)
sser.listen(3)
while True:
print("等等客戶端連接")
conn,addr=sser.accept() #等待連接,會(huì)一直處于阻塞,返回連接對(duì)象和對(duì)方地址
print("有客戶端已經(jīng)連接,IP地址和端口為:",addr)
conn.send(("服務(wù)器歡迎你:%s\r\n"%(str(addr))).encode("gbk")) # 發(fā)送數(shù)據(jù),使用連接對(duì)象操作
while True:
#接收數(shù)據(jù),會(huì)一直阻塞
#使用連接對(duì)象操作
rdata=conn.recv(1024)
if not rdata: break #判斷客戶端是否斷開,斷開則收到空數(shù)據(jù)
print(rdata.decode("gbk"))
conn.send("服務(wù)器返回,收到數(shù)據(jù)\r\n".encode("gbk"))#發(fā)送數(shù)據(jù),使用連接對(duì)象操作
#關(guān)閉連接
sser.close()
客戶端進(jìn)階:
實(shí)現(xiàn)循環(huán)收發(fā)和判斷服務(wù)器是否斷開
import socket
sclient=socket.socket()#得到socket對(duì)象
#連接服務(wù)器
#失敗會(huì)報(bào)錯(cuò):ConnectionRefusedError
sclient.connect(("192.168.1.135",2699))
while True:
#接收數(shù)據(jù),會(huì)一直阻塞
rdata=sclient.recv(1024)
if not rdata: break # 判斷服務(wù)器是否斷開,斷開則收到空數(shù)據(jù)
print(rdata.decode("gbk"))
sclient.send(("客戶端收到數(shù)據(jù):%s\r\n"%rdata.decode("gbk")).encode("gbk")) # 發(fā)送數(shù)據(jù)
#關(guān)閉連接
sclient.close()
注意:
發(fā)送數(shù)據(jù)不可發(fā)送空字符,否則會(huì)卡住,解決方法為判斷輸入的是否為空值,空值則進(jìn)行數(shù)據(jù)發(fā)送
strx=input("輸入:").strip()#得到控制臺(tái)輸入值
if(len(strx)==0):continue #如果為空字符,則跳出本次循環(huán)
print(strx) #打印
sclient.send(strx.encode("gbk")) # 發(fā)送數(shù)據(jù)
發(fā)送大數(shù)據(jù):
先發(fā)送總體數(shù)據(jù)大小,socket另一端判斷實(shí)際接收的數(shù)據(jù)大小與總數(shù)據(jù)大小進(jìn)行比較,循環(huán)recv()進(jìn)行數(shù)據(jù)接收
簡(jiǎn)單的ssh實(shí)現(xiàn):
服務(wù)端:
import os
import socket
sser=socket.socket()#得到socket對(duì)象
sser.bind(("0.0.0.0",2697))#建立監(jiān)聽(tīng)
sser.listen(3)
while True:
print("等等客戶端連接")
conn,addr=sser.accept() #等待連接,會(huì)一直處于阻塞,返回連接對(duì)象和對(duì)方地址
print("有客戶端已經(jīng)連接,IP地址和端口為:",addr)
conn.send(("服務(wù)器歡迎你:%s\r\n"%(str(addr))).encode("gbk")) # 發(fā)送數(shù)據(jù),使用連接對(duì)象操作
while True:
#接收數(shù)據(jù),會(huì)一直阻塞
rdata=conn.recv(1024)
if not rdata: break #判斷客戶端是否斷開,斷開則收到空數(shù)據(jù)
sendtox=os.popen(rdata.decode("gbk")).read() #執(zhí)行命令
conn.send(str(len(sendtox)).encode("gbk")) #發(fā)送執(zhí)行命令的結(jié)果長(zhǎng)度
#如果長(zhǎng)度大于0 則發(fā)送命令結(jié)果數(shù)據(jù)
if len(sendtox)>0:
if conn.recv(10).decode("gbk")=="1":
conn.sendall(sendtox.encode("gbk"))#發(fā)送最終數(shù)據(jù)
#關(guān)閉連接
sser.close()
客戶端:
import socket
sclient=socket.socket()#得到socket對(duì)象
#連接服務(wù)器
#失敗會(huì)報(bào)錯(cuò):ConnectionRefusedError
sclient.connect(("192.168.43.21",2697))
# 接收數(shù)據(jù),會(huì)一直阻塞
rdata = sclient.recv(1024)
print(rdata.decode("gbk"))
while True:
strx = input("請(qǐng)輸入命令:").strip() # 得到控制臺(tái)輸入值
if (len(strx) == 0): continue # 如果為空字符,則跳出本次循環(huán)
sclient.send(strx.encode("gbk")) # 發(fā)送數(shù)據(jù)
rdata = sclient.recv(10)
if not rdata: break # 判斷服務(wù)器是否斷開,斷開則收到空數(shù)據(jù)
#判斷命令是否執(zhí)行成功,0為失敗
dataall=int(rdata.decode("gbk"))
if dataall==0:
continue
sclient.send("1".encode("gbk")) # 發(fā)送確認(rèn)接收數(shù)據(jù)命令
#循環(huán)接收數(shù)據(jù)
datanew=0
while dataall !=datanew:
rdata=sclient.recv(1024).decode("gbk")
datanew+=len(rdata)
print(rdata)
#關(guān)閉連接
sclient.close()
發(fā)送文件:
發(fā)送文件,使用read()讀取文件數(shù)據(jù)后,可循環(huán)調(diào)用send()發(fā)送數(shù)據(jù),或者使用sendall()一次性發(fā)送所有數(shù)據(jù),socket另一端接收可循環(huán)recv()進(jìn)行數(shù)據(jù)接收,且每次接收的數(shù)據(jù)大小是不確定的。文件傳輸需要驗(yàn)證發(fā)送和接受的數(shù)據(jù)是否完全一致,可以通過(guò)數(shù)據(jù)大小加md5雙重驗(yàn)證,發(fā)送端:md5在每次發(fā)送一條數(shù)據(jù)時(shí)進(jìn)行update(),在數(shù)據(jù)發(fā)送完成后再發(fā)送md5值;接受端:md5在每次接收到一條數(shù)據(jù)后進(jìn)行update(),在文件接收完成后再接收發(fā)送端發(fā)送的md5值,將兩值進(jìn)行比較,相同則表示傳輸無(wú)丟包,但加入md5校驗(yàn),將會(huì)影響傳輸速率。
發(fā)送文件數(shù)據(jù):先發(fā)送總體數(shù)據(jù)大小,socket另一端判斷實(shí)際接收的數(shù)據(jù)大小與總數(shù)據(jù)大小進(jìn)行比較,循環(huán)recv()進(jìn)行數(shù)據(jù)接收
示例:客戶端發(fā)送文件名,服務(wù)器判斷文件是否存在,如果不存在或者是空文件則不進(jìn)行傳輸,服務(wù)器進(jìn)行文件發(fā)送,客戶端實(shí)現(xiàn)文件接收
服務(wù)器
import os
import socket
sser=socket.socket()#得到socket對(duì)象
sser.bind(("0.0.0.0",2697))#建立監(jiān)聽(tīng)
sser.listen(3)
while True:
print("等等客戶端連接")
conn,addr=sser.accept() #等待連接,會(huì)一直處于阻塞,返回連接對(duì)象和對(duì)方地址
print("有客戶端已經(jīng)連接,IP地址和端口為:",addr)
conn.send(("服務(wù)器歡迎你:%s\r\n"%(str(addr))).encode("gbk")) # 發(fā)送數(shù)據(jù),使用連接對(duì)象操作
while True:
#接收數(shù)據(jù),會(huì)一直阻塞
rdata=conn.recv(1024)
if not rdata: break #判斷客戶端是否斷開,斷開則收到空數(shù)據(jù)
filesize=0
filenamex=rdata.decode("gbk")
if os.path.isfile(filenamex): #判斷是否是文件
filesize=os.stat(filenamex).st_size #得到文件大小
conn.send(str(filesize).encode("gbk")) #不是文件則發(fā)送0,是文件則是實(shí)際大小
#如果文件大小大于0 則發(fā)送文件
if filesize>0:
if conn.recv(10).decode("gbk")=="1": #等待確認(rèn)接收命令
#一行一行發(fā)送數(shù)據(jù)
f=open(filenamex,"rb")
for linex in f:
conn.sendall(linex)#發(fā)送最終數(shù)據(jù)
#關(guān)閉連接
sser.close()
客戶端
import socket
sclient=socket.socket()#得到socket對(duì)象
#連接服務(wù)器
#失敗會(huì)報(bào)錯(cuò):ConnectionRefusedError
sclient.connect(("192.168.43.21",2697))
# 接收數(shù)據(jù),會(huì)一直阻塞
rdata = sclient.recv(1024)
print(rdata.decode("gbk"))
while True:
filenamex = input("請(qǐng)輸入文件名:").strip() # 得到控制臺(tái)輸入值
if (len(filenamex) == 0): continue # 如果為空字符,則跳出本次循環(huán)
sclient.send(filenamex.encode("gbk")) # 發(fā)送數(shù)據(jù)
rdata = sclient.recv(10)
if not rdata: break # 判斷服務(wù)器是否斷開,斷開則收到空數(shù)據(jù)
#判斷命令是否執(zhí)行成功,0為失敗
dataall=int(rdata.decode("gbk"))
if dataall==0:
print("文件不存在或者為空")
continue
sclient.send("1".encode("gbk")) # 發(fā)送確認(rèn)接收數(shù)據(jù)命令
#打開文件
f=open(filenamex,"wb")
#循環(huán)接收數(shù)據(jù)
datanew=0
while dataall !=datanew:
rdata=sclient.recv(1024)
datanew+=len(rdata)
f.write(rdata)
print("文件(%s)接收完畢"%filenamex)
f.close() #關(guān)閉文件
#關(guān)閉連接
sclient.close()
ScoketServer
服務(wù)端實(shí)現(xiàn)多并發(fā)效果,可以同時(shí)接入多個(gè)客戶端
import socketserver
#建立一個(gè)類,必須繼承 socketserver.BaseRequestHandler 類
class DongSocket(socketserver.BaseRequestHandler):
#必須重寫handle方法
def handle(self):
print("建立新連接,對(duì)方地址為:{}".format(self.client_address))
while True:
try:
self.datax=self.request.recv(1024).decode("gbk") #接收數(shù)據(jù)
print("接收的數(shù)據(jù)為:%s"%self.datax)
self.request.send(("服務(wù)器返回?cái)?shù)據(jù):%s"%self.datax).encode("gbk"))
except Exception as e:
print("斷開,再見(jiàn):{}".format(self.client_address))
break
#參數(shù):(("ip",端口),自定義類)
#ss=socketserver.TCPServer(("0.0.0.0",2351),DongSocket) #與之前的socket服務(wù)器效果一致,同時(shí)只能連接一個(gè)客戶端
ss=socketserver.ThreadingTCPServer(("0.0.0.0",2351),DongSocket) #同時(shí)可以連接多個(gè)客戶端,多并發(fā)
ss.serve_forever()
總結(jié)
以上所述是小編給大家介紹的Python中的Socket 與 ScoketServer 通信及遇到問(wèn)題解決方法 ,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Python Socketserver實(shí)現(xiàn)FTP文件上傳下載代碼實(shí)例
- ERROR 2002 (HY000): Can''t connect to local MySQL server through socket ''/tmp/mysql.sock''
- python SocketServer源碼深入解讀
- Java網(wǎng)絡(luò)通信中ServerSocket的設(shè)計(jì)優(yōu)化方案
- python利用socketserver實(shí)現(xiàn)并發(fā)套接字功能
- Python探索之SocketServer詳解
- 基于python socketserver框架全面解析
- [Java]詳解Socket和ServerSocket學(xué)習(xí)筆記
- ServerSocket默認(rèn)邦定IP實(shí)現(xiàn)過(guò)程詳解
相關(guān)文章
Java byte數(shù)組操縱方式代碼實(shí)例解析
這篇文章主要介紹了Java byte數(shù)組操縱方式代碼實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
python list數(shù)據(jù)等間隔抽取并新建list存儲(chǔ)的例子
今天小編就為大家分享一篇python list數(shù)據(jù)等間隔抽取并新建list存儲(chǔ)的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
python實(shí)現(xiàn)把二維列表變?yōu)橐痪S列表的方法分析
這篇文章主要介紹了python實(shí)現(xiàn)把二維列表變?yōu)橐痪S列表的方法,結(jié)合實(shí)例形式總結(jié)分析了Python列表推導(dǎo)式、嵌套、循環(huán)等相關(guān)操作技巧,需要的朋友可以參考下2019-10-10
Python實(shí)現(xiàn)base64編碼的圖片保存到本地功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)base64編碼的圖片保存到本地功能,涉及Python針對(duì)base64編碼解碼與圖形文件輸出保存相關(guān)操作技巧,需要的朋友可以參考下2018-06-06
python區(qū)塊鏈持久化和命令行接口實(shí)現(xiàn)簡(jiǎn)版
這篇文章主要為大家介紹了python區(qū)塊鏈持久化和命令行接口實(shí)現(xiàn)簡(jiǎn)版,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
Python數(shù)據(jù)正態(tài)性檢驗(yàn)實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了Python數(shù)據(jù)正態(tài)性檢驗(yàn)實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
在PyCharm中控制臺(tái)輸出日志分層級(jí)分顏色顯示的方法
今天小編就為大家分享一篇在PyCharm中控制臺(tái)輸出日志分層級(jí)分顏色顯示的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07

