【Python】TCP與UDP編程

Socket是網絡編程的一個抽象概念。通常我們用一個Socket表示“打開了一個網絡鏈接”,而打開一個Socket需要知道目標計算機的IP地址和端口號,再指定協議類型即可。

客戶端

操作步驟

  1. 創建socket
  2. 建立連接
  3. 接收服務端數據
  4. 發送數據
  5. 斷開連接
# 客戶端代碼
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連接:
s.connect(('127.0.0.1', 9999))
# 接收歡迎消息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 發送數據:
    s.send(data)
    print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()

服務端

操作步驟

  1. 創建socket
  2. 綁定監聽端口
  3. 多線程接收客戶端連接
  4. 數據接收與發送
import socket,threading,time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 監聽端口:
s.bind(('127.0.0.1', 9999))

s.listen(5)
print('Waiting for connection...')

# 每個連接都必須創建新線程(或進程)來處理,
# 否則,單線程在處理連接的過程中,無法接受其他客戶端的連接:
def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)
    
while True:
    # 接受一個新連接:
    sock, addr = s.accept()
    # 創建新線程來處理TCP連接:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

運行截圖

服務端:
服務端
客戶端:
客戶端

UDP

TCP是建立可靠連接,並且通信雙方都可以以流的形式發送數據。相對TCP,UDP則是面向無連接的協議。

使用UDP協議時,不需要建立連接,只需要知道對方的IP地址和端口號,就可以直接發數據包。但是,能不能到達就不知道了。

雖然用UDP傳輸數據不可靠,但它的優點是和TCP比,速度快,對於不要求可靠到達的數據,就可以使用UDP協議。

我們來看看如何通過UDP協議傳輸數據。和TCP類似,使用UDP的通信雙方也分爲客戶端和服務器。服務器首先需要綁定端口:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 綁定端口:
s.bind(('127.0.0.1', 9999))

創建Socket時,SOCK_DGRAM指定了這個Socket的類型是UDP。綁定端口和TCP一樣,但是不需要調用listen()方法,而是直接接收來自任何客戶端的數據:

print('Bind UDP on 9999...')
while True:
    # 接收數據:
    data, addr = s.recvfrom(1024)
    print('Received from %s:%s.' % addr)
    s.sendto(b'Hello, %s!' % data, addr)

recvfrom()方法返回數據和客戶端的地址與端口,這樣,服務器收到數據後,直接調用sendto()就可以把數據用UDP發給客戶端。

客戶端使用UDP時,首先仍然創建基於UDP的Socket,然後,不需要調用connect(),直接通過sendto()給服務器發數據:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 發送數據:
    s.sendto(data, ('127.0.0.1', 9999))
    # 接收數據:
    print(s.recv(1024).decode('utf-8'))
s.close()

從服務器接收數據仍然調用recv()方法。

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