1. 程式人生 > >socket模組的基本使用方法

socket模組的基本使用方法

多多關注:

本人的個人部落格網站[https://www.immisso.com](https://www.immisso.com)

本人的漫畫網站[https://www.ibudm.com](https://www.immisso.com)

socket(中文名稱:套接字)是應用層與傳輸層(TCP/UDP協議)的介面。是對TCP/IP的封裝。是作業系統的通訊機制。應用程式通過socket進行網路資料的傳輸。Python中的socket是我們常用的模組,當然還有socketserver模組(對socket模組的進一步封裝)

socket 通訊方式,常用的主要是兩種 + TCP + UDP

下面以一個例子來介紹Socket程式設計。服務端檔案`base_socket_server.py`,客戶端檔案`base_socket_clent.py`。該例子主要介紹了socket的單連線最簡單的用法,要深入使用。看後續文章

在使用socket模組進行編碼之前我們先介紹一個socket的引數

+ family(地址簇):     1. socket.AF_INET IPv4(預設)     2. socket.AF_INET6 IPv6     3. socket.AF_UNIX用於單一的Unix系統程序間通訊

+ type(型別):     1. socket.SOCK_STREAM 流式socket TCP協議(預設)     2. socket.SOCK_DGRAM 資料報式socket UDP協議     3. socket.SOCK_RAW 原始套接字     4. socket.SOCK_RDM 可靠UDP     5. socket.SOCK_SEQPACKET 可靠的連線資料包服務

### 1.socket最基本用法

服務端`base_socket_server.py`

```python # -*- coding: utf-8 -*- # Created by misso at 2017/8/10

# 匯入socket模組 import socket

# 建立例項 # 預設AF_INET,SOCK_STREAM可以不填寫 sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 定義繫結的ip和port ip_port = ("127.0.0.1",8000)

#繫結監聽 sk.bind(ip_port)

# 監聽 sk.listen()

print("等待接受資料..........") # 接受資料 sock,addr = sk.accept()

# 獲取從客戶端發過來的資料 # 一次獲取1k的資料 # python3.x以上的版本。網路資料的傳送接受都是byte型別。 # 如果傳送的資料是str型別則需要進行編解碼 data = sock.recv(1024) str_data = data.decode("utf8") print(str_data)

# 給客戶端返回資料 msg = "服務端返回的資料:"+str_data sock.send(msg.encode())

# 主動關閉連線 sock.close() ``` 這段程式碼的意思是開啟一個socket服務,客戶端傳送過來訊息後。經過服務端的處理後。再返回給客戶端,然後斷開連線。接下來看客戶端的程式碼。

客戶端`base_socket_client.py`

```python

# -*- coding: utf-8 -*- # Created by misso at 2017/8/10

import socket

# 建立例項 # 預設AF_INET,SOCK_STREAM可以不填寫 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 定義繫結的ip和port ip_port = ("127.0.0.1",8000)

#繫結監聽 client.connect(ip_port)

# 給伺服器傳送資料

str = input("輸入資料:")

client.send(str.encode("utf8"))

data = client.recv(1024) print(data.decode()) client.close()

``` 客戶端的程式碼的意思是,開啟連線,連線到指定埠,使用者輸入資料傳送到服務端,然後接受服務端返回的資料。最後再關閉這個連線

執行結果如下: ![](https://imgs.immisso.com/image/img3.png) ![](https://imgs.immisso.com/image/img4.png)

### 2.客服端連續訊息傳送

上面兩個檔案最後都關閉了連線,我們怎麼保持訊息的連續傳送呢?僅僅是不做關閉就可以了嗎?即使我們註釋掉`base_socket_server.py`檔案裡的st.close()。就會發現依舊是不可以的。我們怎麼實現一次連線,就可以持續傳送呢,我們可以在一次連線成功後做一個while true的迴圈,這樣我們就可以持續傳送訊息了。下面是對程式碼的進一步改寫。

服務端`base_socket_server.py`改寫後的程式碼

```python

# -*- coding: utf-8 -*- # Created by misso at 2017/8/12

# 匯入socket模組 import socket

# 建立例項 # 預設AF_INET,SOCK_STREAM可以不填寫 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 定義繫結的ip和port ip_port = ("127.0.0.1", 8000)

# 繫結監聽 sk.bind(ip_port)

# 監聽 sk.listen()

while True:     print("等待接受資料..........")     # 接受資料     sock, addr = sk.accept()     message = "連線成功"     sock.send(message.encode("utf8"))

    while True:         # 獲取從客戶端發過來的資料         # 一次獲取1k的資料         # python3.x以上的版本。網路資料的傳送接受都是byte型別。         # 如果傳送的資料是str型別則需要進行編解碼         data = sock.recv(1024)         str_data = data.decode("utf8")         print(str_data)

        if str_data == "exit":             break

        # 給客戶端返回資料         msg = "服務端返回的資料:" + str_data         sock.send(msg.encode("utf8"))

    # 主動關閉連線     sock.close() ``` 客戶端`base_socket_client.py`改寫後的程式碼

```python

# -*- coding: utf-8 -*- # Created by misso at 2017/8/12

import socket

# 建立例項 # 預設AF_INET,SOCK_STREAM可以不填寫 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 定義繫結的ip和port ip_port = ("127.0.0.1", 8000)

# 繫結監聽 client.connect(ip_port)

while True:     # 接受訊息     data = client.recv(1024)     print(data.decode("utf8"))     # 給伺服器傳送資料     input_str = input("輸入資料:")

    client.send(input_str.encode("utf8"))

    if input_str == "exit":         break ```

執行結果如下: ![](https://imgs.immisso.com/image/img5.png) ![](https://imgs.immisso.com/image/img6.png)

這樣便實現了一個使用者連續傳送資訊連線不斷開的要求,即使這樣當一個使用者連線的時候,另一個使用者是不能連線的。我們怎樣才能進行多連線呢?這裡我們就會用到多執行緒了,每一個使用者連線開啟一個執行緒。就能保證多使用者同時連線了。

### 3. 多使用者連線

上面也提到了,在實際應用中,我們需要多個使用者連線的,我們可以通過開啟執行緒的方式進行多使用者連線

服務端`middle_socket_server.py`

```python

# -*- coding: utf-8 -*- # Created by misso at 2017/8/12

# 匯入socket、threading模組 import socket import threading

# 建立例項 # 預設AF_INET,SOCK_STREAM可以不填寫 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 定義繫結的ip和port ip_port = ("127.0.0.1", 8000)

# 繫結監聽 sk.bind(ip_port)

# 監聽 sk.listen()

# 定義執行緒執行函式

def handle_sock(sock,addr):     message = "連線成功"     sock.send(message.encode("utf8"))     while True:         # 獲取從客戶端發過來的資料         # 一次獲取1k的資料         # python3.x以上的版本。網路資料的傳送接受都是byte型別。         # 如果傳送的資料是str型別則需要進行編解碼         data = sock.recv(1024)         str_data = data.decode("utf8")         print(str_data)

        if str_data == "exit":             break

        # 給客戶端返回資料         msg = "服務端返回的資料:" + str_data         sock.send(msg.encode("utf8"))     # 主動關閉連線     sock.close() while True:     print("等待接受資料..........")     # 接受資料     sock, addr = sk.accept()     client_thread = threading.Thread(target=handle_sock,args=(sock,addr))     client_thread.start()

```

客戶端`middle_socket_client.py`

```python

# -*- coding: utf-8 -*- # Created by misso at 2017/8/12

import socket

# 建立例項 # 預設AF_INET,SOCK_STREAM可以不填寫 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 定義繫結的ip和port ip_port = ("127.0.0.1", 8000)

# 繫結監聽 client.connect(ip_port)

while True:     # 接受訊息     data = client.recv(1024)     print(data.decode("utf8"))     # 給伺服器傳送資料     input_str = input("輸入資料:")

    client.send(input_str.encode("utf8"))

    if input_str == "exit":         break

```

執行結果如下: ![](https://imgs.immisso.com/image/img7.png) ![](https://imgs.immisso.com/image/img8.png) ![](https://imgs.immisso.com/image/img9.png)

提到多連線我們不得不提另一個模組socketserver。

#### 4.socketserver模組的使用

socketserver模組是對socket的封裝。它也可以進行使用者的多連線(其內部實現原始碼也使用了threading模組)。使用起來更加方便。 服務端`socketserver_socket_server.py`

```python

# -*- coding: utf-8 -*- # Created by misso at 2017/8/12

# 匯入模組 from socketserver import BaseRequestHandler,ThreadingTCPServer

# 定義類 class MyServer(BaseRequestHandler):     # 重寫handle方法     def handle(self):         # 定義連線物件         conn = self.request

        message = "連線成功"         conn.send(message.encode())

        while True:             # 接受客戶端訊息             data = conn.recv(1024)             # 列印接受的訊息             print(data.decode("utf8"))

            #如果接受到exit的訊息,則進行迴圈的退出

            if data == b'exit':                 break

            conn.send(data)         conn.close()

if __name__ == "__main__":

    # 建立多執行緒例項

    server = ThreadingTCPServer(("127.0.0.1",8000),MyServer)

    # 開啟socketserver非同步多執行緒

    server.serve_forever()

```

客戶端`base_socket_client.py`

```python

# -*- coding: utf-8 -*- # Created by misso at 2017/8/12

import socket

# 建立例項 # 預設AF_INET,SOCK_STREAM可以不填寫 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 定義繫結的ip和port ip_port = ("127.0.0.1", 8000)

# 繫結監聽 client.connect(ip_port)

while True:     # 接受訊息     data = client.recv(1024)     print(data.decode("utf8"))     # 給伺服器傳送資料     input_str = input("輸入資料:")

    client.send(input_str.encode("utf8"))

    if input_str == "exit":         break

```

執行結果如下:

![](https://imgs.immisso.com/image/img10.png) ![](https://imgs.immisso.com/image/img11.png) ![](https://imgs.immisso.com/image/img12.png)