1. 程式人生 > >socket套接字編程

socket套接字編程

dal serve pid bsp sans blocking int 關閉 通訊

socket套接字編程

  • 客戶端/服務器架構
1.硬件C/S架構(打印機)
2.軟件C/S架構
  互聯網中處處是C/S架構
  如黃色網站是服務端,你的瀏覽器是客戶端(B/S架構也是C/S架構的一種)
  騰訊作為服務端為你提供視頻,你得下個騰訊視頻客戶端才能看它的視頻)
C/S架構與socket的關系:
我們學習socket就是為了完成C/S架構的開發
詳見網絡通信原理
  • socket什麽
Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。

所以,我們無需深入理解tcp/udp協議,socket已經為我們封裝好了,我們只需要遵循socket的規定去編程,寫出的程序自然就是遵循tcp/udp標準的。

也有人將socket說成ip+port,ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這臺機器上的一個應用程序,ip地址是配置到網卡上的,而port是應用程序開啟的,ip與port的綁定就標識了互聯網中獨一無二的一個應用程序

而程序的pid是同一臺機器上不同進程或者線程的標識
  • 套接字的工作流程
技術分享
先從服務器端說起。服務器端先初始化Socket,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求並處理請求,然後把回應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束。
  • socket()模塊函數用法
import socket

socket.socket(socket_family,socket_type,protocal=0)

socket_family 可以是 AF_UNIX 或 AF_INET。
socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默認值為 0。

獲取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

獲取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)


服務端套接字函數
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通信流程與打電話流程類似))
 
技術分享
 1 #_*_coding:utf-8_*_
 2 __author__ = Linhaifeng
 3 import socket
 4 ip_port=(127.0.0.1,9000)  #電話卡
 5 BUFSIZE=1024                #收發消息的尺寸
 6 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #買手機
 7 s.bind(ip_port) #手機插卡
 8 s.listen(5)     #手機待機
 9 
10 
11 conn,addr=s.accept()            #手機接電話
12 # print(conn)
13 # print(addr)
14 print(接到來自%s的電話 %addr[0])
15 
16 msg=conn.recv(BUFSIZE)             #聽消息,聽話
17 print(msg,type(msg))
18 
19 conn.send(msg.upper())          #發消息,說話
20 
21 conn.close()                    #掛電話
22 
23 s.close()                       #手機關機
24 
25  
服務端 技術分享
 1 #_*_coding:utf-8_*_
 2 __author__ = Linhaifeng
 3 import socket
 4 ip_port=(127.0.0.1,9000)
 5 BUFSIZE=1024
 6 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 7 
 8 s.connect_ex(ip_port)           #撥電話
 9 
10 s.send(linhaifeng nb.encode(utf-8))         #發消息,說話(只能發送字節類型)
11 
12 feedback=s.recv(BUFSIZE)                           #收消息,聽話
13 print(feedback.decode(utf-8))
14 
15 s.close()                                       #掛電話
客戶端

  加上鏈接循環於通信循環

技術分享
 1 import socket
 2 ip_port = (127.0.0.1,8080) #電話卡
 3 buf_size = 1024
 4 
 5 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#買手機
 6 server.bind(ip_port)# 手機插上電話卡
 7 server.listen(5) #手機待機
 8 
 9 while True:                     #新增接收鏈接循環,可以不停的接電話
10     conn,addr = server.accept() #手機接電話
11     print(接%s的電話 %addr[0])
12 
13     while True:                  #新增通信循環,可以不斷的通信,收發消息
14         msg = conn.recv(buf_size)#聽消息
15         if len(msg) == 0 :break # 如果不加這一行,接受不到消息容易發生死循環
16         print(msg,type(msg))
17 
18         conn.send(msg.upper()) # 回消息,把接受到的值返回成大寫
19     conn.close()
20 server.close()
服務端 技術分享
 1 import socket
 2 ip_port = (127.0.0.1,8080) #電話卡
 3 buf_size = 1024 #接受消息的長度
 4 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#買手機
 5 
 6 client.connect(ip_port)
 7 
 8 while True:             #新增通信循環,客戶端可以不斷發收消息
 9     msg = input(>>>:  )
10     if len(msg) == 0:continue
11     client.send(msg.encode(utf-8)) # 發消息,只能發送字節類型
12 
13     data = client.recv(buf_size) # 接受消息,不能超過BUF_SIZE
14     print(data.decode(utf-8))
15 
16 client.close()
客戶端

  



socket套接字編程