天天看點

python中socket套接字實作伺服器和用戶端

文章目錄

    • 一、用socket建立一個伺服器的基本步驟
    • 二、用socket建立一個用戶端的基本步驟
    • 三、服務端與用戶端代碼舉例

一、用socket建立一個伺服器的基本步驟

第1步,建立socket對象。調用socket構造函數。

family的值可以是AF_UNIX(Unix域,用于同一台機器上的程序間通訊),也可以是AF_INET(對于IPV4協定的TCP和 UDP),至于type參數,SOCK_STREAM(流套接字)或者 SOCK_DGRAM(資料封包套接字),SOCK_RAW(raw套接字)。我們一般預設使用TCP傳輸協定:

第2步,将socket綁定到指定位址(IP與端口)上。

bind的參數是一個元組,如果是在本機通信我們可以設定IP和端口如下:

第3步,綁定監聽,以便接受連接配接請求。

n指定了最多等待連接配接數,至少為1,是以最大連接配接數為n+1,接到連接配接請求後,這些請求必須排隊,如果隊列已滿,則拒絕請求。

第4步,伺服器套接字通過socket的accept方法等待客戶請求一個連接配接:

accept()在預設情況下就是阻塞的,如果無用戶端連接配接會一直阻塞下去,沒有時間限制。客戶請求連接配接時,accept方法建立連接配接并傳回伺服器。

accept()傳回:第一個元素(connection)是新的socket對象,伺服器通過它與客戶通信;第二個元素(address)是客戶的internet位址。

第5步,處理階段,伺服器和客戶通過send和recv方法通信(傳輸資料)。

伺服器調用send,并采用字元串形式向客戶發送資訊。send方法傳回已發送的字元個數。伺服器使用recv方法從客戶接受資訊。

調用recv時,必須指定一個整數來控制本次調用所接受的最大資料量。recv方法在接受資料時會進入’blocket’狀态,最後傳回一個字元串,用它來表示收到的資料。如果發送的量超過recv所允許,資料會被截斷。多餘的資料将緩沖于接受端。以後調用recv時,多餘的資料會從緩沖區删除。

此外,要注意 python3.x以上,網絡資料的發送接收都是byte類型,如果發送的資料是str型,則需要編碼和解碼

connection.send(msg.encode())
 data=connection.recv().decode()
           

第6步,傳輸結束,伺服器調用socket的close方法以關閉連接配接。

connection.close()
sock.close()
           

二、用socket建立一個用戶端的基本步驟

第1步,建立一個socket以連接配接伺服器

第2步,使用socket的connect方法連接配接伺服器

ip_port=("127.0.0.1",5005)
socket.connect(ip_port)
           

第3步,客戶和伺服器通過send和recv方法通信。

socket.send(msg.encode())
data=socket.recv().decode()
           

第4步,結束後,客戶通過調用socket的close方法來關閉連接配接。

三、服務端與用戶端代碼舉例

網上服務端的代碼一般像下面這樣:

import socket

#預設tcp方式傳輸
sk=socket.socket()
#綁定IP與端口
ip_port=('127.0.0.1',5005)
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()
           

網上用戶端代碼一般如下:

import socket

#服務端為tcp方式,用戶端也采用tcp方式  預設參數即為tcp
client = socket.socket()
#通路的伺服器的ip和端口
ip_port=('127.0.0.1',5005)
#連接配接主機
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
           

注意:一定要先運作服務端再運作用戶端,否則會連接配接不上。

上面的代碼隻适合作為測試用,隻能進行一次連接配接,一旦用戶端主動或因為異常突然斷開了連接配接,服務端就會因為報錯而停止運作。服務端停止運作也會導緻用戶端異常停止,因而無法實作長久運作。

那麼如何讓服務端和用戶端發生異常後回到等待連接配接的狀态而不是讓程式直接崩掉呢?我的方法是通過 try–except語句來監測異常,發生異常就通過except語句回到等待連接配接的狀态。

服務端:

# -*- coding: utf-8 -*-
"""
Created on Sun Oct 18 16:51:56 2020

@author: HP
"""

import socket

#預設tcp方式傳輸
sk=socket.socket()
#綁定IP與端口
ip_port=('127.0.0.1',5005)
#綁定監聽
sk.bind(ip_port)
#最大連接配接數
sk.listen(5)
#不斷循環 接受資料
str="成功接收到資料:"
while True:
    try:
        #提示資訊
        print("正在等待接收資料。。。。")
        #接受資料  連接配接對象與用戶端位址
        conn, address = sk.accept()
        print('連接配接成功!')
        #定義資訊
        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(str.encode()+data)
        #主動關閉連接配接
        #conn.close()
    except:
        print('error!')
        conn.close()
        continue   #通過continue回到循環開始,等待連接配接
           

用戶端(用戶端對持續運作的要求并不高,可以不這麼做,直接傳回錯誤給使用者讓使用者再次連接配接即可):

# -*- coding: utf-8 -*-
"""
Created on Sun Oct 18 16:48:03 2020

@author: HP
"""
import socket
while True:
    try:
        #服務端為tcp方式,用戶端也采用tcp方式  預設參數即為tcp
        client = socket.socket()
        #通路的伺服器的ip和端口
        ip_port=('127.0.0.1',5005)
        #連接配接主機
        client.connect(ip_port)
        #定義發送消息循環
        while True:
            try:
                # 接受主機資訊   每次接收緩沖區1024個位元組
                data = client.recv(1024)
                # 列印接受的資料
                print(data.decode())
                msg_input = input("請輸入發送的消息:")
                client.send(msg_input.encode())
                if msg_input == 'exit':
                    break
            except:
                print('接收資料或發送資料失敗!')
                break
    except:
        print('無法連接配接服務端!請檢查服務端是否開啟!')
        continue
           

我在網上查找資料的時候發現還有更正規有效的方法,可以用select()方法監聽異常,但是我還不太會,有興趣的話可以參考下面的部落格:

python socket程式設計之select

socket select() 函數詳解