每周一總結,準時為你充電
上周講了1和2部分,這周接著講3和4,希望給以後用到socket編程的同學一些參考。# struct header {
# int buf1;
# double buf2;
# char buf3[11];
# }
此刻,我們就需要用到struct模塊,可以很方便到解決該問題。struct模塊中最重要的三個函數是pack(), unpack(), calcsize()# 按照給定的格式化字符串,把數據封裝成字符串(實際上是類似於c結構體的字節流)string = struct.pack(fmt, v1, v2, ...)# 按照給定的格式(fmt)解析字節流string,返回解析出來的tuple,tuple = unpack(fmt, string)# 計算給定的格式(fmt)佔用多少字節的內存offset = calcsize(fmt)msg = "我正在學習python的網絡編程。"
msg_bs = msg.encode("utf-8") # 將數據編碼轉為字節
res = struct.pack("i", len(msg_bs)) # 將字節數據的長度打包成固定長度(4)
在struct模塊中,將一個整型數字、浮點型數字或字符流(字符數組)轉換為字節流(字節數組)時,需要使用格式化字符串fmt告訴struct模塊被轉換的對象是什麼類型,比如整型數字是'i',浮點型數字是'f',一個ascii碼字符是's'。下表是常見到python類型、字節和格式符號到對應表。小端字節序:低字節存於內存低地址;高字節存於內存高地址大端字節序:高字節存於內存低地址;低字節存於內存高地址。在fomat前面添加如下到符號,代表用什麼字節順序打包成字節流。<little-endian(小字節序)standardnone>big-endian(大字節序)standardnone!network (= big-endian)standardnone那麼上面開頭到那個自定義結構體,該如何打包呢,其實也很簡單。# struct header {
# int buf1;
# double buf2;
# char buf3[11];
# }
bin_buf_all = struct.pack('id11s', buf1, buf2, buf3) ret_all = struct.unpack('id11s', bin_buf_all) 打包後到字節流就可以直接通過socket的send或sendall函數發出。當然通過socket的recv接收的字節流,可以通過struct的unpack成功解包出來。 socket.socket(socket_family,socket_type,protocol=0)socket.AF_UNIX 只能夠用於單一的Unix系統進程間通信socket.SOCK_STREAM 流式socket , for TCP (默認)socket.SOCK_DGRAM 數據報式socket , for UDPsocket.SOCK_RAW 原始套接字,普通的套接字無法處理ICMP、IGMP等網絡報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在需要執行某些特殊操作時使用,如發送ICMP報文。SOCK_RAM通常僅限於高級用戶或管理員運行的程序使用。socket.SOCK_SEQPACKET 可靠的連續數據包服務0 (默認)與特定的地址家族相關的協議,如果是0,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議s.bind() 綁定地址(ip地址,埠)到套接字,參數必須是元組的格式例如:s.bind(('127.0.0.1',8009))s.listen(5) 開始監聽,5為最大掛起的連接數s.accept() 被動接受客戶端連接,阻塞,等待連接s.connect() 連接伺服器端,參數必須是元組格式例如:s.connect(('127,0.0.1',8009))s.recv(1024) 接收TCP數據,1024為一次數據接收的大小s.send(bytes) 發送TCP數據,python3發送數據的格式必須為bytes格式s.sendall() 完整發送數據,內部循環調用sendsocket.recv(bufsize[, flags])socket.send(bytes[, flags])參數:同send,返回值:如果發送成功則返回None 否則返回異常這2個收發函數比較特殊,之前也沒什麼注意他們的參數和返回值,因為這裡涉及到緩衝區到問題。如果建立的另一端連結被斷開, 則recv立即返回空字符串recv是從接受緩衝區取出內容,當緩衝區為空則阻塞recv如果一次接受不完緩衝區的內容,下次執行會自動接受如果發送的另一端不存在則會產生Pipe Broken異常send是從發送緩衝區發送內容,當緩衝區為滿則堵塞所以其實數據真正交互到方式如下。如果當你在寫代碼到時候,發現一些和預期不一樣到結果時候,可以想想是否因為緩衝區到緣故。另外給大家一個可以支撐百萬socket連接的server端代碼,供大家調試參考,主要是利用了python的gevent模塊的高性能。# encoding: utf-8
"""@python: v3.5.4@author: hutong@file: tcpserver.py@time: 2019/5/23 下午2:52"""import geventfrom gevent import monkey; monkey.patch_all()from gevent.server import StreamServer#from __future__ import print_function import json
"""測試socket可以支撐百萬連結的服務端demo""" def handle(socket, address): print(address) while True: data = socket.recv(1024) print(data.decode()) gevent.sleep(1) reback = {'msg':'ok'} socket.send(json.dumps(reback).encode())
if __name__ == "__main__":import sysport = 8088# default backlog is 256server = StreamServer(('127.0.0.1', port), handle, backlog=4096)server.serve_forever()如果文章對你有幫助,
還請幫忙轉發轉發,謝謝。
問題交流/稿件投遞
免費領取例子腳本和代碼
免費入微信群交流
免費PMP考試諮詢
掃一掃,加小T