1. 程式人生 > >Python之路--Python基礎9--Socket編程

Python之路--Python基礎9--Socket編程

主機 make 深入理解 pre odi data splay 異常 inpu

一、socket介紹

  Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。所以,我們無需深入理解tcp/udp協議,socket已經為我們封裝好了,我們只需要遵循socket的規定去編程,寫出的程序自然就是遵循tcp/udp標準的。

二、套接字工作流程

  一個生活中的場景。你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提起電話,這時你和你的朋友就建立起了連接,就可以講話了。等交流結束,掛斷電話結束此次交談。 生活中的場景就解釋了這工作原理。

技術分享圖片

  先從服務器端說起。服務器端先初始化Socket,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求並處理請求,然後把回應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束。

三、Socket模塊函數的用法

服務端套接字函數:

  s.bind()綁定(主機,端口號)到套接字
  s.listen()開始TCP監聽
  s.accept()被動接受TCP客戶的連接,(阻塞式)等待連接的到來



客戶端套接字函數
  s.connect()主動初始化TCP服務器連接
  s.connect_ex()connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常

公共用途的套接字函數
  s.recv() 接收TCP數據
  s.send() 發送TCP數據(send在待發送數據量大於己端緩存區剩余空間時,數據丟失,不會發完)
  s.sendall() 發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩余空間時,數據不丟失,循環調用send直到發完)
  s.recvfrom() 接收UDP數據

  s.sendto() 發送UDP數據
  s.getpeername() 連接到當前套接字的遠端的地址
  s.getsockname() 當前套接字的地址
  s.getsockopt() 返回指定套接字的參數
  s.setsockopt() 設置指定套接字的參數
  s.close() 關閉套接字

面向鎖的套接字方法
  s.setblocking() 設置套接字的阻塞與非阻塞模式
  s.settimeout() 設置阻塞套接字操作的超時時間
  s.gettimeout() 得到阻塞套接字操作的超時時間

面向文件的套接字的函數
  s.fileno() 套接字的文件描述符
  s.makefile() 創建一個與該套接字相關的文件

四、基於TCP的套接字

tcp是基於鏈接的,必須先啟動服務端,然後再啟動客戶端去鏈接服務端。

#TCP服務端

ss = socket()  #創建服務器套接字
ss.bind()      #把地址綁定到套接字
ss.listen()    #監聽鏈接
inf_loop:      #服務器無限循環
    cs = ss.accept()   #接受客戶端鏈接
    comm_loop:         #通訊循環
        cs.recv()/cs.send() #對話(接收與發送)
    cs.close()    #關閉客戶端套接字
ss.close()        #關閉服務器套接字(可選)
#TCP客戶端

cs = socket()     # 創建客戶套接字
cs.connect()      # 嘗試連接服務器
comm_loop:        # 通訊循環
    cs.send()/cs.recv()    # 對話(發送/接收)
cs.close()                 # 關閉客戶套接字

栗子:socket通信流程與打電話流程類似,我們就以打電話為例來實現一個low版的套接字通信:

#服務端

#_*_coding:utf-8_*_
__author__ = YL

import socket
ip_port
=(127.0.0.1,9000) #電話卡 BUFSIZE=1024 #收發消息的尺寸
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #買手機 s.bind(ip_port) #手機插卡 s.listen(5) #手機待機 conn,addr=s.accept() #手機接電話 # print(conn) # print(addr) print(接到來自%s的電話 %addr[0]) msg=conn.recv(BUFSIZE) #聽消息,聽話 print(msg,type(msg)) conn.send(msg.upper()) #發消息,說話 conn.close() #掛電話 s.close() #手機關機
#客戶端

#_*_coding:utf-8_*_
__author__ = YL

import socket
ip_port=(127.0.0.1,9000)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.connect_ex(ip_port)                           #撥電話

s.send(LHF nb.encode(utf-8))                #發消息,說話(只能發送字節類型)

feedback=s.recv(BUFSIZE)                        #收消息,聽話
print(feedback.decode(utf-8))

s.close()                                       #掛電話

加上鏈接循環與通信循環(持續通話)

#服務端
import socket

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)   #買手機
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #就是它,在bind前加
phone.bind(("127.0.0.1", 8080))                             #插入手機卡

phone.listen(5)                                             #開機

while True:      #鏈接循環
    conn, addr = phone.accept()                             #接電話
    print("client :", addr)

    while True:  #通訊循環
        try:
            data = conn.recv(1024)                          #收消息
            if not data:
                break             #針對linux,客戶端斷開鏈接的異常處理
            print("from client msg: %s" % data)
            conn.send(data.upper())                         #發消息
        except Exception:
            break
    conn.close()                                            #掛電話
phone.close()                                               #關機
#客戶端

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client.connect(("127.0.0.1", 8080)) #撥通電話

while True:
    msg = input(">>>: ")
    client.send(msg.encode("utf-8"))

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

client.close()

五、基於UDP的套接字

udp是無鏈接的,先啟動哪一端都不會報錯。

#UDP服務端

ss = socket()   #創建一個服務器的套接字
ss.bind()       #綁定服務器套接字
inf_loop:       #服務器無限循環
    cs = ss.recvfrom()/ss.sendto() # 對話(接收與發送)
ss.close()                         # 關閉服務器套接字

#UDP客戶端

cs = socket()   # 創建客戶套接字
comm_loop:      # 通訊循環
    cs.sendto()/cs.recvfrom()   # 對話(發送/接收)
cs.close()                      # 關閉客戶套接字

栗子:udp套接字簡單示例

#_*_coding:utf-8_*_

import socket
ip_port=(127.0.0.1,9000)
BUFSIZE=1024
udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

udp_server_client.bind(ip_port)

while True:
    msg,addr=udp_server_client.recvfrom(BUFSIZE)
    print(msg,addr)

    udp_server_client.sendto(msg.upper(),addr)

Python之路--Python基礎9--Socket編程