Python中基礎(chǔ)的socket編程實(shí)戰(zhàn)攻略
在網(wǎng)絡(luò)通信中socket幾乎無(wú)處不在,它可以看成是應(yīng)用層與TCP/IP協(xié)議簇通信的中間軟件抽象層,是兩個(gè)應(yīng)用程序彼此進(jìn)行通信的接口,并且把復(fù)雜的TCP/IP協(xié)議細(xì)節(jié)隱藏在接口之后。Python提供了socket模塊,可以非常方便的進(jìn)行socket編程。
創(chuàng)建一個(gè)server socket
使用socket方法創(chuàng)建一個(gè)新的socket,通常提供兩個(gè)參數(shù),第一個(gè)參數(shù)是address family, 第二個(gè)是socket type。
#create an INET, STREAMing socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
以上創(chuàng)建了一個(gè)address family為IP協(xié)議,并且傳輸協(xié)議為TCP的socket。
服務(wù)器端在創(chuàng)建一個(gè)socket之后,需要綁定到一個(gè)IP地址與端口,提供服務(wù),這就要用到bind方法。
# bind the socket to all available interfaces on port 8888
s.bind(('', 8888))
使用listen方法,將socket設(shè)置為監(jiān)聽狀態(tài)。listen方法后面跟一個(gè)參數(shù),表示最多可以在隊(duì)列里面接收的請(qǐng)求數(shù)目。
#become a server socket serversocket.listen(5)
現(xiàn)在,我們已經(jīng)創(chuàng)建了一個(gè)server socket,然后編寫一個(gè)無(wú)限循環(huán)體,接收來(lái)自客戶端的連接,利用accept方法,它返回一個(gè)新的socket,表示與遠(yuǎn)端的連接,同時(shí)返回一個(gè)地址對(duì),表示遠(yuǎn)端連接的IP地址與端口號(hào)。
# enter the main loop of the web server while 1: #accept connections from outside, return a pair (conn, addr) (clientsocket, address) = serversocket.accept() #now do something with the clientsocket #in this case, we'll pretend this is a threaded server ct = client_thread(clientsocket) ct.run()
通常,循環(huán)體中的server socket不會(huì)發(fā)送和接收任何數(shù)據(jù),而僅僅是接收來(lái)自遠(yuǎn)端的連接,將新的連接交給其他的線程去處理,然后就繼續(xù)偵聽更多其他的連接,否則的話在處理一個(gè)連接的時(shí)候,就無(wú)法接受其他新的連接了。
接下來(lái),我們新建一個(gè)線程對(duì)連接進(jìn)行處理。首先,使用recv方法接受來(lái)自socket的數(shù)據(jù),后面帶著一個(gè)參數(shù)表示一次最多可以接受數(shù)據(jù)的大小。然后使用sendall方法回復(fù)socket,sendall不斷發(fā)送數(shù)據(jù)直到所有數(shù)據(jù)發(fā)送完畢或者發(fā)生了異常。最后,需要記得把socket關(guān)閉,因?yàn)槊總€(gè)socket就代表了系統(tǒng)中的一個(gè)文件描述符,如果沒有及時(shí)關(guān)閉,可能會(huì)超過(guò)系統(tǒng)最大文件描述符的數(shù)量,導(dǎo)致無(wú)法創(chuàng)建新的socket。
def handle_request(sock, addr):
print "Accept new connection from {addr}".format(addr = addr)
request_data = client_connection.recv(1024)
print request_data.decode()
http_response = "Hello, world!"
# send response data to the socket
sock.sendall(http_response)
sock.close()
總結(jié)server socket主要由以下幾個(gè)步驟:
- 創(chuàng)建一個(gè)新的server socket;
- 將socket綁定到一個(gè)地址和端口;
- 偵聽遠(yuǎn)程進(jìn)來(lái)的連接;
- 接受連接, 分發(fā)給其他線程處理。
以下是完整的server socket示例代碼:
import socket
import threading
SERVER_ADDRESS = (HOST, PORT) = '', 8888
REQUEST_QUEUE_SIZE = 1024
def handle_request(sock, addr):
print "Accept new connection from {addr}".format(addr = addr)
request_data = client_connection.recv(1024)
print request_data.decode()
http_response = "Hello, world!"
# send response data to the socket
sock.sendall(http_response)
sock.close()
def serve_forever():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# reuse socket immediately
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(SERVER_ADDRESS)
server_socket.listen(REQUEST_QUEUE_SIZE)
print 'Serving HTTP on port {port} ...'.format(port = PORT)
while True:
try:
client_connection, client_address = server_socket.accept()
except IOError as e:
code, msg = e.args
# restart 'accept' if it was interrupted
if code == errno.EINTR:
continue
else:
raise
# create a thread to handle this request
t = threading.Thread(target=handle_request, args=(sock, addr))
t.start()
if __name__ == '__main__':
serve_forever()
創(chuàng)建一個(gè)client socket
客戶端的socket就比較簡(jiǎn)單,主要包括以下幾個(gè)步驟:
- 創(chuàng)建一個(gè)socket;
- 連接到服務(wù)器;
- 給服務(wù)器發(fā)送數(shù)據(jù);
- 接收服務(wù)器返回的數(shù)據(jù);
- 關(guān)閉socket。
import socket
HOST = 'localhost' # the remote host
PORT = 8888 # port used by server
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect to server
client_socket.connect((HOST, PORT))
# send something to the server
client_socket.sendall("Hello, world")
data = client_socket.recv(1024)
client_socket.close()
print 'Received', repr(data)
PS:socket模塊使用引申
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
參數(shù)一:地址簇
socket.AF_INET IPv4(默認(rèn))
socket.AF_INET6 IPv6
socket.AF_UNIX 只能夠用于單一的Unix系統(tǒng)進(jìn)程間通信
參數(shù)二:類型
socket.SOCK_STREAM 流式socket , for TCP (默認(rèn))
socket.SOCK_DGRAM 數(shù)據(jù)報(bào)式socket , for UDP
socket.SOCK_RAW 原始套接字,普通的套接字無(wú)法處理ICMP、IGMP等網(wǎng)絡(luò)報(bào)文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報(bào)文;此外,利用原始套接字,可以通過(guò)IP_HDRINCL套接字選項(xiàng)由用戶構(gòu)造IP頭。
socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數(shù)據(jù)報(bào)但不保證順序。SOCK_RAM用來(lái)提供對(duì)原始協(xié)議的低級(jí)訪問(wèn),在需要執(zhí)行某些特殊操作時(shí)使用,如發(fā)送ICMP報(bào)文。SOCK_RAM通常僅限于高級(jí)用戶或管理員運(yùn)行的程序使用。
socket.SOCK_SEQPACKET 可靠的連續(xù)數(shù)據(jù)包服務(wù)
參數(shù)三:協(xié)議
0 ?。J(rèn))與特定的地址家族相關(guān)的協(xié)議,如果是 0 ,則系統(tǒng)就會(huì)根據(jù)地址格式和套接類別,自動(dòng)選擇一個(gè)合適的協(xié)議
sk.bind(address)
s.bind(address) 將套接字綁定到地址。address地址的格式取決于地址族。在AF_INET下,以元組(host,port)的形式表示地址。
sk.listen(backlog)
開始監(jiān)聽傳入連接。backlog指定在拒絕連接之前,可以掛起的最大連接數(shù)量。
backlog等于5,表示內(nèi)核已經(jīng)接到了連接請(qǐng)求,但服務(wù)器還沒有調(diào)用accept進(jìn)行處理的連接個(gè)數(shù)最大為5
這個(gè)值不能無(wú)限大,因?yàn)橐趦?nèi)核中維護(hù)連接隊(duì)列
sk.setblocking(bool)
是否阻塞(默認(rèn)True),如果設(shè)置False,那么accept和recv時(shí)一旦無(wú)數(shù)據(jù),則報(bào)錯(cuò)。
sk.accept()
接受連接并返回(conn,address),其中conn是新的套接字對(duì)象,可以用來(lái)接收和發(fā)送數(shù)據(jù)。address是連接客戶端的地址。
接收TCP 客戶的連接(阻塞式)等待連接的到來(lái)
sk.connect(address)
連接到address處的套接字。一般,address的格式為元組(hostname,port),如果連接出錯(cuò),返回socket.error錯(cuò)誤。
sk.connect_ex(address)
同上,只不過(guò)會(huì)有返回值,連接成功時(shí)返回 0 ,連接失敗時(shí)候返回編碼,例如:10061
sk.close()
關(guān)閉套接字
sk.recv(bufsize[,flag])
接受套接字的數(shù)據(jù)。數(shù)據(jù)以字符串形式返回,bufsize指定最多可以接收的數(shù)量。flag提供有關(guān)消息的其他信息,通??梢院雎浴?/p>
sk.recvfrom(bufsize[.flag])
與recv()類似,但返回值是(data,address)。其中data是包含接收數(shù)據(jù)的字符串,address是發(fā)送數(shù)據(jù)的套接字地址。
sk.send(string[,flag])
將string中的數(shù)據(jù)發(fā)送到連接的套接字。返回值是要發(fā)送的字節(jié)數(shù)量,該數(shù)量可能小于string的字節(jié)大小。
sk.sendall(string[,flag])
將string中的數(shù)據(jù)發(fā)送到連接的套接字,但在返回之前會(huì)嘗試發(fā)送所有數(shù)據(jù)。成功返回None,失敗則拋出異常。
sk.sendto(string[,flag],address)
將數(shù)據(jù)發(fā)送到套接字,address是形式為(ipaddr,port)的元組,指定遠(yuǎn)程地址。返回值是發(fā)送的字節(jié)數(shù)。該函數(shù)主要用于UDP協(xié)議。
sk.settimeout(timeout)
設(shè)置套接字操作的超時(shí)期,timeout是一個(gè)浮點(diǎn)數(shù),單位是秒。值為None表示沒有超時(shí)期。一般,超時(shí)期應(yīng)該在剛創(chuàng)建套接字時(shí)設(shè)置,因?yàn)樗鼈兛赡苡糜谶B接的操作(如 client 連接最多等待5s )
sk.getpeername()
這個(gè)方法只能用在客戶端,用于查看server端的信息
返回連接套接字的遠(yuǎn)程地址。返回值通常是元組(ipaddr,port)。
sk.getsockname()
這個(gè)方法只能用在server端用與查看server端自己的信息
返回套接字自己的地址。通常是一個(gè)元組(ipaddr,port)
sk.fileno()
套接字的文件描述符
- Python Socket編程之多線程聊天室
- python的socket編程入門
- python多線程socket編程之多客戶端接入
- Python Socket編程詳細(xì)介紹
- Python基礎(chǔ)教程之tcp socket編程詳解及簡(jiǎn)單實(shí)例
- Python的Socket編程過(guò)程中實(shí)現(xiàn)UDP端口復(fù)用的實(shí)例分享
- Python socket編程實(shí)例詳解
- 最基礎(chǔ)的Python的socket編程入門教程
- Python Socket編程入門教程
- 在Python中使用異步Socket編程性能測(cè)試
- python SOCKET編程基礎(chǔ)入門
相關(guān)文章
Python實(shí)現(xiàn)數(shù)字的格式化輸出
這篇文章主要介紹了Python如何實(shí)現(xiàn)數(shù)字的格式化輸出,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-08-08
python統(tǒng)計(jì)字符串中字母出現(xiàn)次數(shù)代碼實(shí)例
這篇文章主要介紹了python統(tǒng)計(jì)字符串中字母出現(xiàn)次數(shù)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
python程序中斷然后接著中斷代碼繼續(xù)運(yùn)行問(wèn)題
這篇文章主要介紹了python程序中斷然后接著中斷代碼繼續(xù)運(yùn)行問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
Python自動(dòng)化部署工具Fabric的簡(jiǎn)單上手指南
這篇文章主要介紹了Python自動(dòng)化部署工具Fabric的簡(jiǎn)單上手指南,涵蓋Fabric的安裝、fabric的遠(yuǎn)程操作與維護(hù)等方面,需要的朋友可以參考下2016-04-04
PyCharm 2021.2 (Professional)調(diào)試遠(yuǎn)程服務(wù)器程序的操作技巧
本文給大家分享用 PyCharm 2021 調(diào)試遠(yuǎn)程服務(wù)器程序的過(guò)程,通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-08-08
pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇1)
這篇文章主要為大家介紹了pygame實(shí)現(xiàn)俄羅斯方塊游戲基礎(chǔ)的第1篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
Python分支語(yǔ)句與循環(huán)語(yǔ)句應(yīng)用實(shí)例分析
這篇文章主要介紹了Python分支語(yǔ)句與循環(huán)語(yǔ)句應(yīng)用,結(jié)合具體實(shí)例形式詳細(xì)分析了Python分支語(yǔ)句與循環(huán)語(yǔ)句各種常見應(yīng)用操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2019-05-05

