Python Day31:socket套接字、TCP協議及其經常使用內置函數、及服務端與客戶端標準代碼

## socket

```python
socket 就是套接字:
CP用主機的IP地址加上主機上的端口號做爲TCP鏈接的端點,這種端點就叫作套接字
它是網絡通訊過程當中端點的抽象表示,包含進行網絡通訊必需的五種信息:鏈接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。
#網絡通訊和鏈接,主要有3個參數:通訊的目的IP地址、使用的傳輸層協議(TCP或UDP)和使用的端口號。Socket原意是 「插座」。經過將這3個參數結合起來,與一個「插座」Socket綁定,應用層就能夠和傳輸層經過套接字接口,區分來自不一樣應用程序進程或網絡鏈接的通訊,實現數據傳輸的併發服務
就是一個封裝好的模塊,要學習的就是模塊的使用方法 
socket分爲兩種類型  
​    AF_UNIX : 進程間通信
​    AF_INET : 網絡通信  
需明確:關於網絡協議 和socket相關概念,對於全部編程語言都是一致的,區別僅僅是各編程語言的函數名稱不一樣
要明確一點:不管是客戶端服務器端都使用的都是socket對象
 
```

## socket內經常使用函數

```python
服務端套接字函數
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()      獲得阻塞套接字操做的超時時間

```

<p style="color:red">注意TCP中必須先啓動服務器再啓動客戶端,不然客戶端因爲沒法連接服務器,直接報錯!</p>

## TCP服務端

```python
import socket
ip_port=('127.0.0.1',8081)#電話卡
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #買手機
s.bind(ip_port) #手機插卡
s.listen(5)     #手機待機

while True:                         #新增接收連接循環,能夠不停的接電話
    conn,addr=s.accept()            #手機接電話
    # print(conn)
    # print(addr)
    print('接到來自%s的電話' %addr[0])
    while True:                         #新增通訊循環,能夠不斷的通訊,收發消息
        msg=conn.recv(BUFSIZE)             #聽消息,聽話
        print(msg,type(msg))
        conn.send(msg.upper())          #發消息,說話
    conn.close()                    #掛電話
s.close()                       #手機關機


```

## TCP客戶端

```python
import socket
ip_port=('127.0.0.1',8081)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect_ex(ip_port)           #撥電話

while True:                             #新增通訊循環,客戶端能夠不斷髮收消息
    msg=input('>>: ').strip()
    if len(msg) == 0:continue
    s.send(msg.encode('utf-8'))         #發消息,說話(只能發送字節類型)
    
    feedback=s.recv(BUFSIZE)                           #收消息,聽話
    print(feedback.decode('utf-8'))
s.close()                                       #掛電話

```

當客服端與服務器連接成功後,若是一方沒有執行close,而是直接強行終止程序(或是遇到異常被迫終止),都會致使另外一方發送問題

linux下,不會拋出異常會致使接收數據的一方,recv方法不斷的收到空消息,形成死循環

要使應用程序可以在不一樣平臺正常工做,那須要分別處理這兩個問題

解決方案以下:

```python
import socket
ip_port=('127.0.0.1',8081)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(ip_port)
s.listen(5)    
while True:                        
    conn,addr=s.accept()           
    while True:                         
        try:
            msg=conn.recv(BUFSIZE)             
            #linux不會拋出異常,會接收到空消息,這裏加以判斷
            if not msg:
                conn.close()
                break
            print(msg,type(msg))
            conn.send(msg.upper())        
       except ConnectionResetError:
            #只要異常發生則意味着對方以及關閉了,服務器也相應的關閉該連接
            conn.close()
            break
    conn.close()              
s.close()                       

```

至此TCP通信模板程序就完成了,能夠不斷的接收新的連接,不斷的收發消息,而且不會由於客戶端強制關閉而異常退出!
相關文章
相關標籤/搜索