基於Python的Socket編程

Socket基礎

Socket的英文原義是"孔"或"插座",最初作爲BSD UNIX的進程通信機制,也被稱作"套接字",用於描述IP地址和端口,是一個通信鏈的句柄,可用來實現不同虛擬機或不同計算機之間的通信。在Internet上的主機一般運行了多個服務軟件,同時提供幾種服務。每種服務都打開一個Socket,並綁定到一個端口上,不同的端口對應於不同的服務。

基於服務器端和客戶端的Socket原語

在這裏插入圖片描述

  • socket():建立socket對象,相當於“打開”操作。socket原語的參數通常包括使用的傳輸層協議類型、網絡層地址類型等。
  • bind():綁定。參數傳入要綁定的IP地址和端口。
    IP地址必須是主機上的一個可用的地址(當主機上存在多個IP時,綁定地址0.0.0.0可以監聽所有可用的IP);
    端口必須是一個該Socket協議未被佔用的端口,若一主機上的多個程序試圖同時綁定到80端口時,只有一個程序能成功。
    服務器端程序在listen()之前必須進行bind()操作,客戶端程序若在connect()原語之前沒調用bind(),系統會自動分配一個未被佔用的地址和端口。
  • listen():監聽。只在服務器端有用,告訴操作系統開始監聽之前綁定的IP地址和端口,可在參數中指定允許排隊的最大連接數量
  • connect():在客戶端連接服務器。參數中需指定服務器端的地址和端口。要麼與服務器端完成TCP 3次握手並建立連接,要麼連接服務器失敗
  • accept():接收連接。只在服務器端有用,從監聽到的連接中取出一個,並將其包裝成一個新的Socket對象。完成accept()標誌着Socket已完成了TCP鏈路建立階段的3次握手。若無客戶端連接請求,則accept()調用會阻塞等待。
  • send():發送數據。以bytes類型進行數據的傳輸
  • recv():接收數據。若Socket中無消息可讀取,默認情況下recv()調用會被阻塞直至有消息到達
  • close():關閉連接。一方調用,另一方收到後也調用close()關閉連接。

包socket封裝了所有Python的原生Socket操作

實戰在線(一):Socket TCP

TCP-Serverse.py:

'''TCP-Socket服務器端'''
import socket
import datetime

HOST = '0.0.0.0'	#IP
PORT = 3434			#端口

#AF_INET說明使用IPv4地址,SOCK_STREAM指明TCP
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((HOST,PORT))         #綁定IP與端口
s.listen(1)                 #監聽

while True:
    conn,addr = s.accept()                          #接受TCP連接,並返回新的Socket對象
    print ('Client %s connected!' % str(addr))      #輸出客戶端的IP地址
    dt = datetime.datetime.now()
    message = "Current time is "+str(dt)
    mes_change = bytes(message,encoding='utf-8')    #將str類型轉碼爲經過編碼後的bytes類型
    conn.send(mes_change)                           #向客戶端發送當前時間
    print("Sent:",message)
    conn.close()                                    #關閉連接

TCP-Client.py:

'''TCP-Socket客戶端'''
import socket
import os

HOST = '127.0.0.1'
PORT = 3434

#AF_INET說明使用IPv4地址,SOCK_STREAM指明TCP協議
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.connect((HOST,PORT))
print("Connect %s:%d OK" % (HOST,PORT))
data = s.recv(1024)             #接收最大長度爲1024的數據
print ("Received: ",data)
s.close()                       #關閉連接

os.system('pause')              #暫停程序,避免直接結束,看不到結果

效果圖:
在這裏插入圖片描述
注意:先運行服務器端代碼TCP-Serverse.py:,再運行客戶端代碼TCP-Client.py
服務器端代碼主體處於while循環中,故程序將不斷監聽並一直運行,當有客戶端連接成功後將當前系統時間發送給客戶端並馬上關閉連接
客戶端的Socket端口號由系統自動分配

實戰在線(二):Socket UDP

UDP相對於TCP在傳輸層提供更少的控制,沒有建立連接、斷開等概念,所以基於UDP的Socket通信過程也比TCP稍微簡單。在UDP中可直接通過指定IP:Port進行數據收發。UDP Socket可以複用TCP中的socket()和bind()原語,除此之外,UDP屬於自己的Socket原語如下:

  • recvfrom():從綁定的地址接收數據
  • sendto():向指定的地址發送數據,在調用的參數中應該傳入通信對端的地址和端口

UDP-Serverse.py:

'''UDP-Socket服務器端'''
import socket

HOST = '0.0.0.0'    #IP
PORT = 3434         #端口

#AF_INET說明使用IPv4地址,SOCK_DGRAM指明UDP
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind((HOST,PORT))         #綁定IP與端口

while True:
    data,addr = s.recvfrom(1024)    #本次接收最大數據長度爲1024
    print('Receiverd:%s from %s' % (data,str(addr)))

s.close()

UDP-Client.py:

'''UDP-Socket客戶端'''
import socket
import os

HOST = '127.0.0.1'
PORT = 3434

#AF_INET說明使用IPv4地址,SOCK_DGRAM指明UDP協議
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

data = 'Hello UDP!!!'
data_change = bytes(data,encoding='utf-8')
s.sendto(data_change,(HOST,PORT))
print('Sent:%s to %s:%d'%(data,HOST,PORT))
s.close()                       #關閉連接

os.system('pause')              #暫停程序,避免直接結束,看不到結果

效果圖:
在這裏插入圖片描述
注意:先運行服務器端代碼UDP-Serverse.py:,再運行客戶端代碼UDP-Client.py
客戶端直接調用sendto()向指定的地址發送數據
客戶端端口63140由客戶端程序在調用sendto()時自動生成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章