pythonsocket自定义协议_小渣渣学习笔记 python day28【tcp聊天 udp聊天 粘包 自定义协议 struct模块】...
tcp 實現(xiàn)聊天功能
server端
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',22000))
sk.listen()
while True: #同時連多個人
obj,addr = sk.accept() #三次握手在這里完成
while True:
msg = input('>>>')
if msg.upper() == 'Q':break
obj.send(msg.encode('utf-8'))
content = obj.recv(1024).decode('utf-8')
print(content)
obj.close()
sk.close()
client端
import socket
sk = socket.socket() #實例化socket對象
sk.connect(('127.0.0.1',22000)) #生成連接
while True:
content = sk.recv(1023).decode('utf-8') #接受內(nèi)容
print(content) #打印內(nèi)容
msg = input('>>>')
if msg.upper() == 'Q':break
sk.send(msg.encode('utf-8')) #發(fā)送內(nèi)容
sk.close() #關(guān)閉
udp 實現(xiàn)聊天功能
server端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1',22000))
while True:
msg,addr = sk.recvfrom(1204)
print(msg.decode('utf-8'))
msg = input('>>>')
if msg.upper()=='Q':break
sk.sendto(msg.encode('utf-8'),addr)
sk.close()
client端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM) #實例化socket對象
while True:
msg = input('>>>')
if msg.upper()=='Q':break
sk.sendto(msg.encode('utf-8'),('127.0.0.1',22000))
msg,addr = sk.recvfrom(1111)
print(msg.decode('utf-8'))
sk.close() #關(guān)閉
粘包現(xiàn)象
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
conn,addr = sk.accept()
conn.send(b'aa') #分別發(fā)送aa 和 bb
conn.send(b'bb')
conn.close()
sk.close()
import socket
import time
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
time.sleep(0.1) #sleep 0.1s
msg1 = sk.recv(1024)
print(msg1) #b'aabb' 本來aa 和bb 應(yīng)該分別在msg1 和msg2 打印出來的,現(xiàn)在放在一起打印了,就因為前面有了一個sleep了0.1秒,這就是粘包現(xiàn)象
msg2 = sk.recv(1024)
print(msg2) #b''
sk.close()
#粘包現(xiàn)象(只發(fā)生在tcp協(xié)議中)
#發(fā)生在發(fā)送端,消息很短,放在緩存池中,操作系統(tǒng)固定間隔再發(fā)送
#發(fā)生在接收端,接受不及時
#只發(fā)生在tcp協(xié)議,因為tcp協(xié)議多條消息之間沒有邊界,并且還有一大堆優(yōu)化算法
#tcp協(xié)議中為什么存在沒有邊界,
#udp協(xié)議 網(wǎng)絡(luò)最大帶寬限制 MTU = 1500字節(jié)
#tcp沒有上限,如果文件比較大,可以拆開
#解決粘包關(guān)鍵是設(shè)置邊界
#【作業(yè)】 socket 發(fā)送文件
#治療一下粘包
#server端
import socket
ipaddr = '127.0.0.1'
port = 10001
sk = socket.socket()
sk.bind((ipaddr,port))
sk.listen()
conn,addr = sk.accept()
msg1 = input('>>>').encode('utf-8') #輸入‘你是猴子請來的救兵么’并轉(zhuǎn)成bytes
msg2 = input('>>>').encode('utf-8') #輸入‘是的’
num = str(len(msg1)) #計算第一次輸入的字符串字節(jié)數(shù),限制字節(jié)數(shù)為9999
print(num) #30 因為一個漢字utf-8 占3個字節(jié),10個字
len1 = num.zfill(4) #補全數(shù)字到4位,client客戶端就要先接收4位
conn.send(len1.encode('utf-8'))
conn.send(msg1)
conn.send(msg2)
conn.close()
sk.close()
#client端
import socket
import time
ipaddr = '127.0.0.1'
port = 10001
sk = socket.socket()
sk.connect((ipaddr,port))
time.sleep(0.2)
len1 = int(sk.recv(4).decode('utf-8')) #先接收4位
msg1 = sk.recv(len1).decode('utf-8')
msg2 = sk.recv(1024).decode('utf-8')
print(msg1) #打印 ‘你是猴子請來的救兵么’
print(msg2) #打印‘是的’
sk.close()
#以上就是我自定義的協(xié)議,第一次發(fā)送最多9999字節(jié)的字符串
#下面學習一個新的模塊 struct
import struct
num1 = 129469649
num2 = 2342
num3 = 1
ret = struct.pack('i',num1) #i代表4個字節(jié) b代表1個字節(jié) H 和h 代表2個字節(jié) d是8位
print(ret) #b'\xd1\x8c\xb7\x07' 4個字節(jié)
ret2 = struct.pack('i',num2)
print(ret2) #b'&\t\x00\x00' 4個字節(jié)
ret3 = struct.pack('i',num3)
print(ret3) #b'\x01\x00\x00\x00' 4個字節(jié)
#struct.pack() 可以把任意數(shù)字轉(zhuǎn)成4個字節(jié)
#還可以轉(zhuǎn)回來
print(struct.unpack('i',ret)) #(129469649,) 得到的是一個元組,第一個元素就是
print(struct.unpack('i',ret2)) # (2342,)
print(struct.unpack('i',ret3)) #(1,)
#那么上面的server端 自定義協(xié)議處,先發(fā)送字節(jié)就可以變更一下
#server端
import socket
import struct
ipaddr = '127.0.0.1'
port = 10001
sk = socket.socket()
sk.bind((ipaddr,port))
sk.listen()
conn,addr = sk.accept()
msg1 = input('>>>').encode('utf-8') #輸入‘你是猴子請來的救兵么’并轉(zhuǎn)成bytes
msg2 = input('>>>').encode('utf-8') #輸入‘是的’
# num = str(len(msg1)) #計算第一次輸入的字符串字節(jié)數(shù),限制字節(jié)數(shù)為9999
# len1 = num.zfill(4) #補全數(shù)字到4位,client客戶端就要先接收4位
blen = struct.pack('i',len(msg1))
# msg1是轉(zhuǎn)成bytes后的類型,主要是先發(fā)到對方msg1的長度len(msg1)比如等于233,client端要先接收到233
# 然后根據(jù)233,recv(233)接收233個字節(jié)數(shù)的字節(jié),再展示出來
# 我不能send一個len(msg1)這樣的int數(shù)字過去,但是可以把len(msg1)用struct.pack()轉(zhuǎn)成byte類型傳過去,
# 過去之后再struct.unpack(),再轉(zhuǎn)成int類型len1,送給recv(len1)
conn.send(blen) # 這里blen已經(jīng)是bytes類型,就不用encode了
conn.send(msg1)
conn.send(msg2)
conn.close()
sk.close()
#client端
import socket
import struct
import time
ipaddr = '127.0.0.1'
port = 10001
sk = socket.socket()
sk.connect((ipaddr,port))
len1 = struct.unpack('i',sk.recv(4))[0]
#先接收4位byte類型,sk.recv(4) ,完了以后再把他struct.unpack()一下,得到是元組,取第一個元素[0],就是首先發(fā)過來的長度
#struct 可以一句話搞定自定義發(fā)送協(xié)議
msg1 = sk.recv(len1).decode('utf-8')
msg2 = sk.recv(1024).decode('utf-8')
print(msg1) #打印 ‘你是猴子請來的救兵么’
print(msg2) #打印‘是的’
sk.close()
#后續(xù)為了防止粘包,豈不是每次都要先發(fā)送長度,再根據(jù)長度接收內(nèi)容?
#【練習】
#1、基于tcp協(xié)議的登陸認證:客戶端輸入用戶名密碼,發(fā)送到服務(wù)器端,服務(wù)器端認證,發(fā)送結(jié)果到客戶端
#2、基于udp協(xié)議的多人聊天,自動識別用戶 不能用ip和port
#3、基于tcp協(xié)議完成一個文件的上傳,先處理小文件,在處理大文件
#4、選課系統(tǒng)
#總結(jié)
#tcp協(xié)議
#socket 模塊引用
#sk的創(chuàng)建
#conn的創(chuàng)建
#接收多個客戶端的請求,while True的位置
#怎么退出
#udp協(xié)議
#語法 socket創(chuàng)建的區(qū)別,加參數(shù)type
#涉及的發(fā)送和接收新方法 sendto recvfrom
#和tcp協(xié)議區(qū)別
#聊天程序
#粘包現(xiàn)象
#tcp協(xié)議的特點?三次握手連接,四次揮手斷開
#什么是粘包,發(fā)送端發(fā)送數(shù)據(jù)頻率高,下層來不及發(fā)送,固定時間間隔統(tǒng)一發(fā)送,接收端來不及接收
#怎么處理?先發(fā)送長度,根據(jù)長度接收內(nèi)容
#自定義協(xié)議
#struct模塊應(yīng)用
#不用struct能不能自定義協(xié)議?根據(jù)發(fā)送字節(jié)長度int用zfill方法換算成固定字節(jié)長度的數(shù)值,傳到接收端,接收端根據(jù)數(shù)值轉(zhuǎn)成int,再根據(jù)int接收內(nèi)容
總結(jié)
以上是生活随笔為你收集整理的pythonsocket自定义协议_小渣渣学习笔记 python day28【tcp聊天 udp聊天 粘包 自定义协议 struct模块】...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pythonmail添加附件_Pytho
- 下一篇: din算法 代码_DIN算法代码详细解读