Socket
網絡上的兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。
Socket又稱"套接字",應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求,使主機間或者一臺計算機上的進程間可以通訊。
Python 提供了兩個級別訪問的網絡服務。:
- 低級別的網絡服務支持基本的 Socket,它提供了標準的 BSD Sockets API,可以訪問底層操作系統Socket接口的全部方法。
- 高級別的網絡服務模塊 SocketServer, 它提供了服務器中心類,可以簡化網絡服務器的開發。
注意:以下實例中全部使用本地局域網 若想實現外網傳輸 在有路由器的情況下需首先向運營商申請公網動態ip 然后添加內網映射等操作
?
?
socket()函數
Python 中,我們用 socket()函數來創建套接字,語法格式如下:
import socket
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)#所給即為默認參數
參數
family:
- socket.AF_INET? ? ??IPv4(默認)
- socket.AF_INET6? ? IPv6
- socket.AF_UNIX? ? ? 只能夠用于單一的Unix系統進程間通信
type: ?
- socket.SOCK_STREAM 流式socket, for TCP (默認)
- socket.SOCK_DGRAM ? 數據報式socket, for UDP
- socket.SOCK_RAW ? ? ? ?原始套接字
- socket.SOCK_RDM ? ?可靠UDP形式
- socket.SOCK_SEQPACKET? ? 可靠的連續數據包服務
protocol:
- 0:默認,可以省略
- CAN_RAW或CAN_BCM:地址族為AF_CAN時
Socket 對象(內建)方法
| 函數 | 描述 |
|---|---|
| 服務器端套接字 | |
| s.bind() | 綁定地址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示地址。 |
| s.listen() | 開始TCP監聽。backlog指定在拒絕連接之前,操作系統可以掛起的最大連接數量。該值至少為1,大部分應用程序設為5就可以了。 |
| s.accept() | 被動接受TCP客戶端連接,(阻塞式)等待連接的到來 |
| 客戶端套接字 | |
| s.connect() | 主動初始化TCP服務器連接,。一般address的格式為元組(hostname,port),如果連接出錯,返回socket.error錯誤。 |
| s.connect_ex() | connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常 |
| 公共用途的套接字函數 | |
| s.recv() | 接收TCP數據,數據以字符串形式返回,bufsize指定要接收的最大數據量。flag提供有關消息的其他信息,通常可以忽略。 |
| s.send() | 發送TCP數據,將string中的數據發送到連接的套接字。返回值是要發送的字節數量,該數量可能小于string的字節大小。 |
| s.sendall() | 完整發送TCP數據,完整發送TCP數據。將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常。 |
| s.recvfrom() | 接收UDP數據,與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址。 |
| s.sendto() | 發送UDP數據,將數據發送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。 |
| s.close() | 關閉套接字 |
| s.getpeername() | 返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)。 |
| s.getsockname() | 返回套接字自己的地址。通常是一個元組(ipaddr,port) |
| s.setsockopt(level,optname,value) | 設置給定套接字選項的值。 |
| s.getsockopt(level,optname[.buflen]) | 返回套接字選項的值。 |
| s.settimeout(timeout) | 設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因為它們可能用于連接的操作(如connect()) |
| s.gettimeout() | 返回當前超時期的值,單位是秒,如果沒有設置超時期,則返回None。 |
| s.fileno() | 返回套接字的文件描述符。 |
| s.setblocking(flag) | 如果flag為0,則將套接字設為非阻塞模式,否則將套接字設為阻塞模式(默認值)。非阻塞模式下,如果調用recv()沒有發現任何數據,或send()調用無法立即發送數據,那么將引起socket.error異常。 |
| s.makefile() | 創建一個與該套接字相關連的文件 |
?
?
簡單的信息交互實例(tcp):
服務端? socket_server.py
import
socket
#
默認tcp方式傳輸
sk=
socket.socket()
#
綁定IP與端口
ip_port=(
'
127.0.0.1
'
,8888
)
#
綁定監聽
sk.bind(ip_port)
#
最大連接數
sk.listen(5
)
#
不斷循環 接受數據
while
True:
#
提示信息
print
(
"
正在等待接收數據。。。。
"
)
#
接受數據 連接對象與客戶端地址
conn, address =
sk.accept()
#
定義信息
msg =
"
連接成功
"
#
返回信息
#
注意 python3.x以上,網絡數據的發送接收都是byte類型
#
如果發送的數據是str型,則需要編碼
conn.send(msg.encode())
#
不斷接收客戶端發來的消息
while
True:
#
接收客戶端消息
data = conn.recv(1024
)
print
(data.decode())
#
接收到退出指令
if
data == b
'
exit
'
:
break
#
處理客戶端信息 本實例直接將接收到的消息重新發回去
conn.send(data)
#
主動關閉連接
conn.close()
客戶端? socket_client.py
import
socket
#
服務端為tcp方式,客戶端也采用tcp方式 默認參數即為tcp
client =
socket.socket()
#
訪問的服務器的ip和端口
ip_port=(
'
127.0.0.1
'
,8888
)
#
連接主機
client.connect(ip_port)
#
定義發送消息循環
while
True:
#
接受主機信息 每次接收緩沖區1024個字節
data = client.recv(1024
)
#
打印接受的數據
print
(data.decode())
msg_input
= input(
"
請輸入發送的消息:
"
)
client.send(msg_input.encode())
if
msg_input ==
'
exit
'
:
break
運行結果:
服務端
客戶端
但是這種tcp方式我們可以發現一次只能有一個客戶端在運行,我們可以使用更強大的socketserver包來實現非堵塞型tcp連接
非堵塞型信息交互實例(tcp)
相對于上面堵塞型實例,我們僅需要修改服務端文件即可實現多個客戶端與服務端信息交互
socket_server_tcp2.py
#
非阻塞模塊
import
socketserver
#首先我們需要
定義一個類
class
MySocketServer(socketserver.BaseRequestHandler):
#
首先執行setup方法,然后執行handle方法,最后執行finish方法
#
如果handle方法報錯,則會跳過
#
setup與finish無論如何都會執行
#
一般只定義handle方法即可
def
setup(self):
pass
def
handle(self):
#
定義連接變量
conn=
self.request
#
提示信息
print
(
"
連接成功
"
)
#
發送消息定義
msg=
"
Hello World!
"
#
發送消息
conn.send(msg.encode())
#
進入循環 不斷接收客戶端消息
while
True:
#
接收客戶端消息
data=conn.recv(1024
)
#
打印消息
print
(data.decode())
if
data==b
'
exit
'
:
break
conn.send(data)
conn.close()
def
finish(self):
pass
if
__name__
==
'
__main__
'
:
#
提示信息
print
(
"
正在等待接收數據。。。。
"
)
#
創建多線程實例
server=socketserver.ThreadingTCPServer((
"
127.0.0.1
"
,8888
),MySocketServer)
#
開啟異步多線程,等待連接
server.serve_forever()
接著我們可以測試,首先運行socket_server_tcp2.py,然后發現現在可以同時運行多個socket_client.py與服務端進行通信
?
UDP通信實例
總所周知UDP是不可靠的傳輸協議?
服務端socket_server_udp.py
import
socket
#
創建實例 并指定udp參數
sk = socket.socket(type=
socket.SOCK_DGRAM)
#
定義綁定的ip和port
ip_port = (
'
127.0.0.1
'
,8888
)
#
綁定監聽
sk.bind(ip_port)
print
(
"
正在等待接收數據
"
)
#
循環接收數據
while
True:
#
接收數據
data = sk.recv(1024
)
#
打印數據
print
(data.decode())
客戶端socket_client_udp
import
socket
#
實例化對象
sk = socket.socket(type=
socket.SOCK_DGRAM)
#
定義需要連接的的ip和port
ip_port = (
'
127.0.0.1
'
,8888
)
#
循環輸入數據
while
True:
#
輸入發送的信息
msg_input = input(
"
請輸入發送的消息:
"
)
#
接收到退出指令
if
msg_input == b
'
exit
'
:
break
#
與tcp不同 udp使用sendto函數來發送消息
sk.sendto(msg_input.encode(),ip_port)
sk.close()
結果:
服務端
客戶端
?
?
文件傳輸實例:
文件傳輸其實就是比信息交互多了文件IO操作
文件接收端(服務端)file_receive.py:
import
socket
#
實例化
sk =
socket.socket()
#
定義連接的ip和port
ip_port = (
'
127.0.0.1
'
,9999
)
#
綁定端口
sk.bind(ip_port)
#
最大連接數
sk.listen(5
)
#
進入循環接收數據
conn, address =
sk.accept()
print
(
"
文件接收開始
"
)
while
True:
with open(
'
file
'
,
'
ab
'
) as f:
#
接收數據
data = conn.recv(1024
)
if
data == b
'
quit
'
:
break
#
寫入文件
f.write(data)
#
接受完成標志
conn.send(
'
success
'
.encode())
print
(
"
文件接收完成
"
)
#
關閉連接
sk.close()
文件發送端(客戶端)file_send.py:
import
socket
#
實例化
sk =
socket.socket()
#
定義連接的ip和port
ip_port = (
'
127.0.0.1
'
,9999
)
#
服務器連接
sk.connect(ip_port)
#
文件上傳
#
打開文件
with open(
'
D:\pythonwork\socket\socket_server_tcp2.py
'
,
'
rb
'
) as f:
#
按每一段分割文件上傳
for
i
in
f:
sk.send(i)
#
等待接收完成標志
data=sk.recv(1024
)
#
判斷是否真正接收完成
if
data != b
'
success
'
:
break
#
給服務端發送結束信號
sk.send(
'
quit
'
.encode())
進行測試,首先運行file_receive.py 然后運行file_send.py 可以發現文件傳輸成功
打開file文件 可以發現寫入成功 這就實現了簡單的文件傳輸操作
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

