天天看點

python 找不到socket_python應用之socket程式設計

tcp/udp下的socket的基本使用

基于tcp的socket

Tcp是基于連結的,必須先啟動服務端,然後啟動用戶端進行連結

服務端:

ss = socket() #建立伺服器套接字

ss.bind() #把位址綁定到套接字

ss.listen() #監聽連結

inf_loop: #伺服器無限循環

cs = ss.accept() #接受用戶端連結

comm_loop: #通訊循環

cs.recv()/cs.send() #對話(接收與發送)

cs.close() #關閉用戶端套接字

ss.close() #關閉伺服器套接字(可選)

用戶端:

cs = socket() #建立客戶套接字

cs.connect() #嘗試連接配接伺服器

comm_loop: #通訊循環

cs.send()/cs.recv() #對話(發送/接收)

cs.close() #關閉客戶套接字

簡單的實作:

這裡是單個的 一次通信

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

mport socket #AF_INET 基于網絡通信, SOCK_STREAM(基于流的,tcp)

phone= socket.socket(socket.AF_INET, socket.SOCK_STREAM) #買手機

phone.bind(('127.0.0.1', 8000)) #綁定手機卡

phone.listen(5) #開機(監聽) # 5表示 最多有5個可以發送連接配接, 放在連結池中

print('--->')

conn, addr= phone.accept() #(等電話,等待連接配接,會阻塞)(觸發的是3次握手)

#收發消息(在tcp協定中觸發的是資料傳輸)#注意收發資訊不是用手機, 而是conn這條連接配接

mesg = conn.recv(1024) #收消息

print('用戶端發來的消息是:',mesg)

conn.send(mesg.upper())#發消息

#斷開連結 (在tcp協定中觸發的是4次揮手)

conn.close()#關機

phone.close()

服務端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

importsocket

phone= socket.socket(socket.AF_INET, socket.SOCK_STREAM) #買手機

phone.connect(('127.0.0.1', 8000)) #撥通電話 (觸發的是三次握手)

#收發資料#phone.send('hello'.encode('utf-8')) # socket不支援字元串發送,僅支援位元組編碼發送是以要用

phone.send(bytes('hello', encoding='utf-8')) #這兩個發送一樣,隻要轉換成二進制就行

data = phone.recv(1024)print('收到服務端發來的消息', data)

用戶端

這個是簡單的互動模式

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-14 下午5:56#@Author : LK#@File : fu_ceshi.py#@Software: PyCharm

from socket import *buffersize= 1024

#tcp_server = socket(AF_INET, SOCK_STREAM) #流式套接字

tcp_server.bind(('127.0.0.1', 8000))

tcp_server.listen(5)#為了接收多個連接配接

whileTrue:#等待連接配接

conn, add = tcp_server.accept() #等待連接配接 ,會阻塞

print('雙向連接配接是:',conn)print('用戶端位址是',add)#收發資訊

whileTrue:#try:

#這個異常實在win中,但是在linux下有時候是死循環, 因為用戶端突然斷掉,conn就沒了,mesg一直是空

mesg =conn.recv(buffersize)if notmesg:print('用戶端你斷開連接配接了')break

print('服務端接收的資訊:',mesg.decode('utf-8'))

conn.send(mesg.upper())print('服務端以發送回去')#except Exception:

#break

conn.close()#關閉連接配接

tcp_server.close()

服務端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

from socket import *buffersize=1024tcp_client=socket(AF_INET, SOCK_STREAM)#主動連接配接

tcp_client.connect(('127.0.0.1', 8000))#收發資訊

whileTrue:

send_mesg= input('請輸入要個服務端發送的資訊,break停止').strip('')#如果發送的是空格,重新發送

if not send_mesg: continue

if send_mesg == 'break':print('用戶端停止發送資訊了')break

else:

tcp_client.send(send_mesg.encode('utf-8'))print('用戶端已發送消息')

mesg=tcp_client.recv(buffersize)print('用戶端接受的資訊:',mesg.decode('utf-8'))#關閉連接配接

tcp_client.close()

用戶端

基于udp的socket

udp是無連結的,先啟動哪一端都不會報錯

服務端:

ss= socket() #建立一個伺服器的套接字

ss.bind() #綁定伺服器套接字

inf_loop: #伺服器無限循環

cs = ss.recvfrom()/ss.sendto() #對話(接收與發送)

ss.close() #關閉伺服器套接字

用戶端

cs= socket() #建立客戶套接字

comm_loop: #通訊循環

cs.sendto()/cs.recvfrom() #對話(發送/接收)

cs.close() #關閉客戶套接字

udp基本實作:

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-15 下午1:38#@Author : LK#@File : udp_服務端.py#@Software: PyCharm

from socket import *ip_port= (('127.0.0.1', 8080))

buffsize= 1024udp_server= socket(AF_INET, SOCK_DGRAM) #資料報套接字

udp_server.bind(ip_port)whileTrue:

data, addr=udp_server.recvfrom(buffsize)print('用戶端發來的消息',data.decode('utf-8'))

udp_server.sendto(data.upper(), addr)#注意這裡是addr

udp_server.close()

udp服務端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-15 下午1:38#@Author : LK#@File : udp_用戶端.py#@Software: PyCharm

from socket import *ip_port= (('127.0.0.1', 8080))

buffsize= 1024udp_client= socket(AF_INET, SOCK_DGRAM) #資料包套接字

whileTrue:try:

mesg= input('>>>').strip()

udp_client.sendto(mesg.encode('utf-8'), ip_port)#recvfrom 接受的是一個元祖, 裡面是資訊和對方位址

data, addr =udp_client.recvfrom(buffsize)print('服務端發來的是', data.decode('utf-8'))#print(data)

exceptKeyboardInterrupt as e:print(e)print('程式異常中斷')break

#recv 在自己這端的緩沖區為空時,會阻塞(傳回的是資訊)#recvfrom 不會阻塞 (傳回是一個元祖,分别是接受的資訊和位址)

#tcp沒有實作并發,而udp預設實作了,因為udp不用建立連接配接,直接網端口發送,而tcp需要建立連接配接

udp用戶端

udp的用戶端可以開多個,

常用函數

服務端套接字函數

s.bind() 綁定(主機,端口号)到套接字

s.listen() 開始TCP監聽

s.accept() 被動接受TCP客戶的連接配接,(阻塞式)等待連接配接的到來

用戶端套接字函數

s.connect() 主動初始化TCP伺服器連接配接

s.connect_ex() connect()函數的擴充版本,出錯時傳回出錯碼,而不是抛出異常

公共用途的套接字函數

s.recv() 接收TCP資料

s.send() 發送TCP資料(send在待發送資料量大于己端緩存區剩餘空間時,資料丢失,不會發完)

s.sendall() 發送完整的TCP資料(本質就是循環調用send,sendall在待發送資料量大于己端緩存區剩餘空間時,資料不丢失,循環調用send直到發完)

s.recvfrom() 接收UDP資料

s.sendto() 發送UDP資料

s.getpeername() 連接配接到目前套接字的遠端的位址

s.getsockname() 目前套接字的位址

s.getsockopt() 傳回指定套接字的參數

s.setsockopt() 設定指定套接字的參數

s.close() 關閉套接字

面向鎖的套接字方法

s.setblocking() 設定套接字的阻塞與非阻塞模式

s.settimeout() 設定阻塞套接字操作的逾時時間

s.gettimeout() 得到阻塞套接字操作的逾時時間

面向檔案的套接字的函數

s.fileno() 套接字的檔案描述符

s.makefile() 建立一個與該套接字相關的檔案

tcp粘包問題

首先要知道socket的收發消息的原理

python 找不到socket_python應用之socket程式設計

send 是發送給用 對方後,存在對方的核心态中,

recv 收消息是從自己的緩存中收

隻有tcp有粘包現象,udp沒有,但是udp會發生丢包問題, 就是發的資料太多,到那時udp的緩沖區,隻能接收固定大小,剩下的就丢了, 是以udp沒有tcp可靠

流程就是, 服務端發送資料給自己的緩沖區,然後通過網絡發送給用戶端的緩沖區,

用戶端從自己的緩沖區進行取資料,recv函數 一次可能取不完,就可能會出現粘包問題

如果recv取的少的話,或者發送的過多,就可能會出現粘包問題

Recv 是從自己的 核心态中去資料, 如果資料過多的話就會出現粘包問題

解決粘包問題思路: 可以先擷取消息的大小, 然後死循環一直發,知道發送到指定大小在停止, 收包也是如此

所謂粘包問題主要還是因為接收方不知道消息之間的界限,不知道一次性提取多少位元組的資料所造成的。

粘包的表現

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-16 上午8:42#@Author : LK#@File : tcp_粘包問題_服務端.py#@Software: PyCharm

#粘包問題發生的原因:#第一種情況:tcp在發送的時候,基于流的方式發送資料,發送端要等緩沖區滿後才發送出去,造成粘包#(發送資料的時間很短,資料很小,就會和在一起發送)

#第二種情況,發送端發送的資料很大,但是接收端的緩沖區已經放不下,直接從緩沖區裡面拿#多次都從緩沖區裡面取資料(就是發送的大,但是取的少)

#解決方法:一般是先發送一個資料大小,然後回複一下,在用循環發送資料,進階辦法(struct),跟進階(偏函數)

from socket import *tcp_socket=socket(AF_INET, SOCK_STREAM)

ip_port= (('127.0.0.1', 8080))

tcp_socket.bind(ip_port)

tcp_socket.listen(5)

conn, addr=tcp_socket.accept()print('連接配接的資訊',conn)print('詳細資訊',addr)#收發資料

whileTrue:#'''第二種粘包現象,就是發的多,每次收的少'''

#mesg = conn.recv(2)

#print('第一次接受的',mesg.decode('utf-8'))

#mesg = conn.recv(1)

#print('第二次接受的',mesg.decode('utf-8'))

#mesg = conn.recv(1)

#print('第三次接受的',mesg.decode('utf-8'))

'''第一種粘包現象, 發的少收得多'''mesg= conn.recv(1024)print('第一次接受的',mesg.decode('utf-8'))

mesg= conn.recv(1)print('第二次接受的',mesg.decode('utf-8'))

mesg= conn.recv(1)print('第三次接受的',mesg.decode('utf-8'))

coon.close()

tcp_socket.close()

粘包的表現_服務端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-16 上午8:41#@Author : LK#@File : tcp_粘包問題_用戶端.py#@Software: PyCharm

from socket import *tcp_client=socket(AF_INET, SOCK_STREAM)

ip_port= (('127.0.0.1',8080))

tcp_client.connect(ip_port)#收發消息

whileTrue:'''第一中粘包現象,發的少,收的多'''tcp_client.send('第一次發送的'.encode('utf-8'))

tcp_client.send('第二次發送的'.encode('utf-8'))

tcp_client.send('第三次發送的'.encode('utf-8'))

tcp_client.recv(4)#'''第二種粘包現象,發的多收的少'''

#tcp_client.send(b'hhhh')

#tcp_client.send(b'ff')

#tcp_client.recv(4)

粘包的表現_用戶端

圖解模式:

粘包的本質:接收端不知道,從緩存中取多少

第一種粘包現象:

接收端

python 找不到socket_python應用之socket程式設計

發送端

python 找不到socket_python應用之socket程式設計

運作結果

python 找不到socket_python應用之socket程式設計

第二種粘包現象

接收端

python 找不到socket_python應用之socket程式設計

發送端

python 找不到socket_python應用之socket程式設計

結果

python 找不到socket_python應用之socket程式設計

tcp模拟終端,shell執行結果來顯示 粘包問題并解決

如果是linux下 ,不用修改, 輸入ls 顯示目前目錄下的檔案,然後輸入ifconfig 檢視ip等資訊,傳回的資訊比較多,一次不能提取完,再輸入其他指令就會産生錯誤

windows 中 如果産生編碼錯誤就把utf-8 改成gbk

指令用win下的 如 dir 然後 ipconfig 再輸入 其他的

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#存在粘包問題

importsubprocessfrom socket import *

from tcp_模拟終端處理資料 importdealwith

ip_port= (('127.0.0.1', 9000))

buffsize= 1024tcp_server=socket(AF_INET, SOCK_STREAM)try:

tcp_server.bind(ip_port)

tcp_server.listen(5)print('還沒有人連接配接')#等待多個連接配接

whileTrue:try:

conn, addr=tcp_server.accept()print('用戶端連接配接資訊', conn)print('用戶端位址', addr)#收發消息

whileTrue:

mesg=conn.recv(buffsize)if notmesg:print('用戶端中斷連接配接了,伺服器等待下次連接配接')break

print('用戶端發送的是', mesg.decode('utf-8'))

data=dealwith(mesg)#将這些封裝成了一個函數

'''# # 處理從用戶端接收的資訊

# # res是接收的資訊,經過shell腳本處理後的結果

# res = subprocess.Popen(mesg.decode('utf-8'), shell=True,

# stdin=subprocess.PIPE,

# stdout=subprocess.PIPE,

# stderr=subprocess.PIPE

# )

# # 擷取錯誤資訊

# err = res.stderr.read().decode('utf-8')

# if not err:

# data = res.stdout.read().decode('utf-8')

# else:

# data = err'''conn.sendall(data)print('服務端已發送')exceptKeyboardInterrupt as e:print('外部強制結束')breakconn.close()exceptOSError as e:print('端口以用過')

tcp_server.close()

模拟終端_産生粘包_服務端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#存在粘包問題

from socket import *tcp_client=socket(AF_INET, SOCK_STREAM)

ip_port= (('127.0.0.1', 9000))

buffsize= 1024tcp_client.connect(ip_port)whileTrue:#mesg = input('>>>').strip()

#去除左右空格

mesg = input('>>>').lstrip().rstrip()if not mesg: continuetcp_client.send(mesg.encode('utf8'))print('用戶端已發送')

data=tcp_client.recv(buffsize)if notdata:print('服務端發來的是空資訊')continue

print('服務端發來的資訊是:',data.decode('utf-8'))

tcp_client.close()

模拟終端_産生粘包_用戶端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-15 下午5:23#@Author : LK#@File : tcp_模拟終端處理資料.py#@Software: PyCharm

importsubprocessdefdealwith(mesg):#處理從用戶端接收的資訊

#res是接收的資訊,經過shell腳本處理後的結果

res = subprocess.Popen(mesg.decode('utf-8'), shell=True,

stdin=subprocess.PIPE,

stdout=subprocess.PIPE,

stderr=subprocess.PIPE

)#擷取錯誤資訊

err =res.stderr.read()if noterr:

data=res.stdout.read()if notdata:#data = '你輸入的資料傳回值為空'.encode('utf-8')

return '你輸入的資料傳回值為空'.encode('utf-8')else:

data=errreturndata#這裡傳回的是一個位元組的形式

#res = subprocess.Popen('ls', shell=True,#stdin=subprocess.PIPE,#stdout=subprocess.PIPE,#stderr=subprocess.PIPE#)## stdin=subprocess.PIPE, 标準輸入, 輸入的内容會放在管道中## stdout=subprocess.PIPE, 标準輸出,就是結果會放在pipe這個管道中## stderr=subprocess.PIPE, 标準錯誤,如果結果錯誤 會放在這個管道中#

## 讀取管道内容## print(res.stdout.read()), 讀取之後,管道裡面的就沒有輸出了

資料處理

第一種處理粘包的方法:

思路: 在發送端首先發送給接受端一個4個位元組大小的資料,内容是要發的真是資料的大小.接收端在取資料的時候取4個位元組,

然後給發送端發送一個準備接受的信号,當發送端接收到這個信号時,開始發送資訊.接收端開始循環接收資訊.

struct的用法

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

importsubprocessfrom socket import *

from tcp_模拟終端處理資料 importdealwith

ip_port= (('127.0.0.1', 9000))

buffsize= 1024tcp_server=socket(AF_INET, SOCK_STREAM)try:

tcp_server.setsockopt(SOL_SOCKET, SO_REUSEPORT,1)

tcp_server.bind(ip_port)

tcp_server.listen(5)print('還沒有人連接配接')#等待多個連接配接

whileTrue:try:

conn, addr=tcp_server.accept()print('用戶端連接配接資訊', conn)print('用戶端位址', addr)#收發消息

whileTrue:

mesg=conn.recv(buffsize)if notmesg:print('用戶端中斷連接配接了,伺服器等待下次連接配接')break

print('用戶端發送的是', mesg.decode('utf-8'))

data=dealwith(mesg)#解決粘包:,發送端先發送一個消息的大小,接收端回複一個準備接收的信号,然後發送端開始循環發送資訊

length =len(data)

conn.send(str(length).encode('utf-8'))

read_send= conn.recv(buffsize).decode('utf-8')#注意這裡的問題,就是發送一個大的檔案,用sendall,,如何發送,還是在于如何取

if read_send == 'read_recv':

conn.sendall(data)print('服務端已發送')exceptKeyboardInterrupt as e:print('外部強制結束')breakconn.close()exceptOSError as e:print('端口以用過')#tcp_server.close()

tcp_server.close()

解決粘包問題_low版_服務端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#low版解決粘包問題

from socket import *

importsys

tcp_client=socket(AF_INET, SOCK_STREAM)

ip_port= (('127.0.0.1', 9000))

buffsize= 1024tcp_client.connect(ip_port)#3 用connect_ex()比較好, 可以重複利用 端口

whileTrue:#去除左右空格

mesg = input('>>>').lstrip().rstrip()if not mesg: continuetcp_client.send(mesg.encode('utf8'))print('用戶端已發送')

data_lenth= int(tcp_client.recv(1024).decode('utf-8'))#解決粘包問題

tcp_client.send('read_recv'.encode('utf-8'))

recv_leng=0

data= b''

while recv_leng buffsize:

data+=tcp_client.recv(buffsize)

recv_leng=len(data)else:#當剩餘的資料 小于緩沖區大小時

data += tcp_client.recv(data_lenth -recv_leng)

recv_leng=len(data)if notdata:print('服務端發來的是空資訊')continue

print('服務端發來的資訊是:', data.decode('utf-8'))

tcp_client.close()

解決粘包問題_low版_用戶端

第二種處理粘包方法:推薦使用

思路struct,發送端用struct.pack() (一般用int類型占4個位元組) 将要發送的資料的大小打包後發送過去,然後在發送真實資料.兩個必然會粘包.

但是接收端在接收的時候先接收4個位元組,然後用struct.unpack()解包,得到資料大小,再利用循環接受真實資料.

struct用法:

http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#用struct 解決粘包

importstructimportsubprocessfrom socket import *

from tcp_模拟終端處理資料 importdealwith

ip_port= (('127.0.0.1', 9000))

buffsize= 1024tcp_server=socket(AF_INET, SOCK_STREAM)#這一句是 重複利用 端口

try:

tcp_server.setsockopt(SOL_SOCKET, SO_REUSEPORT,1)

tcp_server.bind(ip_port)

tcp_server.listen(5)print('還沒有人連接配接')#等待多個連接配接

whileTrue:try:

conn, addr=tcp_server.accept()print('用戶端連接配接資訊', conn)print('用戶端位址', addr)#收發消息

whileTrue:

mesg=conn.recv(buffsize)if notmesg:print('用戶端中斷連接配接了,伺服器等待下次連接配接')break

print('用戶端發送的是', mesg.decode('utf-8'))

data=dealwith(mesg)#解決粘包:,發送端先發送一個消息的大小,接收端回複一個準備接收的信号,然後發送端開始循環發送資訊

length =len(data)

conn.send(struct.pack('i', length))

conn.sendall(data)print('服務端已發送')exceptKeyboardInterrupt as e:print('外部強制結束')breakconn.close()exceptOSError as e:print('端口以用過')#tcp_server.close()

tcp_server.close()

解決粘包-服務端_推薦使用

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

#struct解決粘包

from socket import *

importstruct

tcp_client=socket(AF_INET, SOCK_STREAM)

ip_port= (('127.0.0.1', 9000))

buffsize= 1024tcp_client.connect(ip_port)whileTrue:#mesg = input('>>>').strip()

#去除左右空格

mesg = input('>>>').lstrip().rstrip()if not mesg: continuetcp_client.send(mesg.encode('utf8'))print('用戶端已發送')#解決粘包

#服務端會發送過來一個 資料的大小,和 一個真實資料的包,兩個必定會粘包,但是解包是分開來解,先解4個位元組(對方發來的資料包大小)

data_length = tcp_client.recv(4)

length= struct.unpack('i', data_length)[0]#循環接收資料

recv_leng =0

data= b''

while recv_leng buffsize:

data+=tcp_client.recv(buffsize)

recv_leng=len(data)else:

data+= tcp_client.recv(length-recv_leng)

recv_leng=len(data)if notdata:print('服務端發來的是空資訊')continue

print('服務端發來的資訊是:', data.decode('utf-8'))

tcp_client.close()

解決粘包-用戶端

udp 的丢包問題

# udp傳輸資料是以資料報的方式發送,每次發送都是發送完整的資料,但是接收方接收的可能小于發送放,就會産生丢包

# 因為每次都是發送一個完整的,取時也是取完緩沖區,是以不會發生粘包,但是會發生丢包,意味着,這是不安全的

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

from socket import *udp_server=socket(AF_INET, SOCK_DGRAM)

ip_port= (('127.0.0.1',8080))

udp_server.bind(ip_port)#收發消息

whileTrue:#這裡的6 出現兩個漢字是因為, 漢字的編碼方式不同(3個位元組,在win中不同)

data, addr = udp_server.recvfrom(6)print('第一次接收的資訊是:',data.decode('utf-8'))

data, addr= udp_server.recvfrom(6)print('第二次接收的資訊是',data.decode('utf-8'))#udp_server.sendto(data,addr)

服務端

python 找不到socket_python應用之socket程式設計
python 找不到socket_python應用之socket程式設計

from socket import *udp_client=socket(AF_INET, SOCK_DGRAM)

ip_port= (('127.0.0.1', 8080))

buffsize= 1024

whileTrue:

data= '第一次發送的資訊'udp_client.sendto(data.encode('utf-8'), ip_port)

data= '第二次發送的資訊'udp_client.sendto(data.encode('utf-8'), ip_port)

udp_client.recvfrom(10)

用戶端

socket_server實作并發

基于tcp的套接字,關鍵就是兩個循環,一個連結循環,一個通信循環

socketserver子產品中分兩大類:server類(解決連結問題)和request類(解決通信問題)

#這樣就tcp伺服器就能被多個使用者連結了, 用戶端流程不變

classMyServer(socketserver.BaseRequestHandler):defhandle(self):#self.request # 相當于 conn

#self.client_address # 相當于 addr

whileTrue:'''在這裡寫收發消息'''s= socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer) #将上面的類執行個體化一個

s.serve_forever() #一直開啟狀态

tcp_socket_server并發版_服務端

importsocketserverimportstructfrom 封裝處理粘包_拆包 importUnPacket, SendDataclassMyServer(socketserver.BaseRequestHandler):defhandle(self):

self.requestprint('連接配接人的資訊')print('conn是', self.request) #conn

print('addr是', self.client_address) #addr

whileTrue:'''收發消息'''head_data= self.request.recv(4)if not head_data: breakreal_data=UnPacket(head_data, self.request)print('用戶端發來的是:%s用戶端位址是是%s' % (real_data.decode('utf-8'), self.client_address))#回複用戶端,防止粘包

send_data = 'aaaaaaaa'SendData(send_data, self.request)if __name__ == '__main__':#pass

print('還沒有人連接配接')

s= socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer) #多線程

#s = socketserver.ForkingTCPServer(('127.0.0.1', 8080), MyServer) # 多程序win中不行

#伺服器一直開着

s.serve_forever()

用戶端

from socket import *

from 封裝處理粘包_拆包 importUnPacket, SendDataimportstruct

tcp_server=socket(AF_INET, SOCK_STREAM)

ip_port= ('127.0.0.1', 8080)

buffsize= 1024tcp_server.connect_ex(ip_port)whileTrue:'''收發資訊'''mesg= input('>>>').strip()#防止粘包處理函數

SendData(mesg, tcp_server)

mesg= tcp_server.recv(4)if not mesg: breakrecv_data=UnPacket(mesg, tcp_server)print('服務端發送的資訊是',recv_data.decode('utf-8'))

tcp_server.close()

處理粘包的問題,封裝了一下後是:

封裝處理粘包_拆包

importstruct#傳過來包的頭部資訊,和連接配接,傳回接受的資料是一個byte類型

defUnPacket(head_data ,conn):

buffsize= 4

'''解決粘包,需要傳送過資料頭,和連接配接'''real_data_length= struct.unpack('i',head_data)[0]

real_data= b''recv_length=0#這個少了點優化

#while recv_length < real_data_length:

#real_data += conn.recv(1024)

#recv_length = len(real_data)

while recv_length buffsize:

real_data+=conn.recv(buffsize)

recv_length=len(real_data)else:

real_data+= conn.recv(real_data_length-recv_length)

recv_length=len(real_data)returnreal_data#接受要發送的資料,是字元串,和要發送的連結(用戶端發送tcp_server, 服務端發送conn或self.request))

defSendData(real_data,conn):'''發送包,發兩次,'''head_length= struct.pack('i', len(real_data)) #後面是一個整數,是以是四個位元組, 這裡有個優化

conn.send(head_length)

conn.sendall(real_data.encode('utf-8'))print('用戶端發送成功')