1. 程式人生 > >TCP伺服器和客戶端的建立(socket/socketserver)

TCP伺服器和客戶端的建立(socket/socketserver)

1 本文記錄針對python網路程式設計學習過程中的socket部分進行記錄與總結,內容僅僅涉及最粗淺的部分,日後或許會進行更新與擴充套件。
2 本文涉及的socket資料傳輸均使用bytes型別,因此在python3環境下,需要特別注意字串的編碼解碼

1 socket模組

A pair (host, port) is used for the AF_INET address family, where host is a string representing either a hostname in Internet domain notation like ‘daring.cwi.nl’ or an IPv4 address like ‘100.50.200.5’, and port is an integer.
For IPv4 addresses, two special forms are accepted instead of a host address: the empty string represents INADDR_ANY

, and the string ‘’ represents INADDR_BROADCAST. This behavior is not compatible with IPv6, therefore, you may want to avoid these if you intend to support IPv6 with your Python programs.

  • 建立socket物件,socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  • 根據官方文件說明,socket接受兩種特殊形式的IPv4的地址。空白地址代表INADDR_ANY
    ,允許任意地址接入;而字串’<broadcast>’則代表INADDR_BROADCAST

1.1 建立TCP伺服器 - socket.socket()

from socket import *
from time import ctime

HOST = ''               # 允許任意host接入
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)   # 繫結地址
tcpSerSock.listen(5
) # 最多同時監聽數量上限為5 while True: print('waiting for connection...') # 接受客戶端請求之前保持阻塞,連線後獲取客戶端socket及其地址 tcpCliSock, addr = tcpSerSock.accept() # 列印請求此次服務的客戶端的地址 print('...connection from: {}'.format(addr)) while True: # 通過客戶socket獲取客戶端資訊(bytes型別),並解碼為字串型別 data = tcpCliSock.recv(BUFSIZ).decode('utf8') if not data: break # 處理字串並重新編碼為bytes型別,呼叫send()方法傳送回客戶端 tcpCliSock.send('[{}] {}'.format(ctime(), data).encode('utf8')) # 關閉客戶端 tcpCliSock.close() # 關閉伺服器 tcpCliSock.close()

1.2 建立TCP客戶端 - socket.socket()

from socket import *

HOST = 'localhost'              # 指定客戶端訪問host
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)        # 連線地址

while True:
    # 使用者輸入資料(str型別)
    data = input('> ')
    if not data:
        break
    # 將資料進行編碼,再通過send()方法傳送給之前繫結的地址伺服器
    tcpCliSock.send(data.encode('utf8'))
    # 接收伺服器返回的資料(bytes型別),解碼為字串型別
    data = tcpCliSock.recv(BUFSIZ).decode('utf8')
    if not data:
        break
    # 列印字串
    print(data)
# 關閉客戶端,斷開連線
tcpCliSock.close()

1.3 終端互動

本地連線互動

1.3

遠端連線互動
  • 更改client的host為遠端主機地址
    2.3 遠端連線互動

2 socketserver模組

  • 建立TCPServer物件,class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

  • 繼承基類RequestHandlerClass,重寫自己的MyRequestsHandler

    class socketserver.BaseRequestHandler

    This is the superclass of all request handler objects. It defines the interface, given below. A concrete request handler subclass must define a new handle() method, and can override any of the other methods. A new instance of the subclass is created for each request.
    handle()
    This function must do all the work required to service a request. The default implementation does nothing. Several instance attributes are available to it; the request is available as self.request; the client address as self.client_address; and the server instance as self.server, in case it needs access to per-server information.
    The type of self.request is different for datagram or stream services. For stream services, self.request is a socket object; for datagram services, self.request is a pair of string and socket.

2.1 建立TCP伺服器 - socketserver.TCPServer()

from socketserver import TCPServer as TCP
from socketserver import StreamRequestHandler as SRH
from time import ctime

HOST = ''
PORT = 21567
ADDR = (HOST, PORT)

# 重寫自己的RequestHandlerClass類
class MyRequestsHandler(SRH):
    # override處理資料的方法,基類預設該方法為空
    def handle(self):
        # 列印客戶端的地址資訊,該資訊被儲存在self.client_address中
        print('connected from: {}'.format(self.client_address))
        # self.rfile.readline()讀取客戶端傳送的資訊(bytes型別),並解碼為字串型別
        # 寫入字串型別資訊,編碼為bytes(此處沒有send()方法)
        self.wfile.write('[{}] {}'.format(ctime(), self.rfile.readline().decode('utf8')).encode('utf8'))

# 構造socketserver.TCPServer類,傳入地址和handler方法引數
tcpServ = TCP(ADDR, MyRequestsHandler)
print('waiting for connection...')
# 開啟該服務,直至中斷
tcpServ.serve_forever()

2.2 建立TCP客戶端 - socket.socket()

from socket import *

HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)

while True:
    tcpCliSock = socket(AF_INET, SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    data = input('> ')
    if not data:
        break
    # 以行終止符作為結尾,傳送字串資訊並編碼
    tcpCliSock.send('{}\r\n'.format(data).encode('utf8'))
    # 接收服務端傳回的資料並解碼
    data = tcpCliSock.recv(BUFSIZ).decode('utf8')
    if not data:
        break
    print(data.strip())
    tcpCliSock.close()

2.3 終端互動

本地連線互動

2.3

遠端連線互動
  • 更改client的host為遠端主機地址
    2.3 遠端連線互動

參考資料