Python 簡單的socket編程(TCP)

  • 問題描述

個人認爲,Socket編程是一個很重要的東西,無論是什麼語言,用到Socket編程的一定有很多,所以,學習Socket編程是很重要的。個人學習Socket編程的原因,是因爲自己覺得學Python有一段時間了,想要做個桌面應用程序出來,首先要搞定Socket編程,所以就開始學習了。下面介紹一下簡單的Socket編程。

 

  • 解決方法

直接上代碼,分爲兩個程序,一個是服務端的程序,用於接收其他的tcp連接,另一個是客戶端的程序,用於請求連接。

首先,是服務端的程序:

import socket

HOST = '0.0.0.0'  
PORT = 8000

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    while True:
        conn, addr = s.accept()
        print('Connected by', addr)
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)
            print('get data ', data.decode('utf-8'))

這裏host寫的是0.0.0.0,指的是允許所有的IP進行tcp連接,如果設置爲127.0.0.1,則就是本機訪問,除了服務器程序運行以外的機器無法進行訪問。

port就是指端口,指定tcp通過哪個端口進行連接

接下來就是生成socket對象,這裏需要說明的是,有的程序生成socket對象使用的是 

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

這個和上面代碼中的 

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:

 效果是一樣的,問題在於,使用第一個代碼時,我們進行完連接以後,需要手動的進行close。

sock.close()

 而如果使用with語句,那麼我們就不需要自己手動設置close,程序能夠幫助我們自動關閉,如果你能理解文件操作裏面的open 和 with open,那麼我相信你也能理解這裏with的意思。

socket.AF_INET 指通過ipv4連接,socket.SOCK_STREAM 指通過tcp連接

s.bind 指將套接字綁定到我們之前指定的地址

s.listen 指開始進行監聽tcp連接

接下來進行死循環

conn, addr = s.accept()       接受TCP鏈接並返回(conn, address),其中conn是新的套接字對象,可以用來接收和發送數據,address是連接客戶端的地址。

接下來再次進行死循環,上一次的死循環,能夠讓我們建立連接以後,發送多次消息,而這一次的死循環,是循環接收數據,因爲我們接收數據是

data = conn.recv(1024)

即接收1024字節,所以,如果我們發送的字節超過了1024字節,那麼我們就進行下一次循環,繼續接收1024字節,就一直死循環,直到所有的字節接受完,然後就 break 退出

conn.sendall(data) 指返回數據給客戶端,sendall指一次性發送所有的數據,因爲如果我們要發送的數據超過了1024字節,用send方法發送數據的話,一次性是發送不完的,是需要用死循環進行發送的, 但是如果我們用sendall,就不用死循環發送了。需要注意的是,我們收到或者發送的數據是bytes格式的,所以我們在發送數據時,需要用encode,將接收的數據變成字符串時,我們需要用decode。

 

接下來是客戶端程序

import socket

HOST = '192.168.5.135'  # 服務器的主機名或者 IP 地址
PORT = 8000        # 服務器使用的端口

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.settimeout(5)
    while True:
        try:
            a = input('please input:')
            s.sendall(a.encode('utf-8'))
            data = s.recv(1024)
            print('Received', data.decode('utf-8'))
        except socket.timeout as e:
            print('time out')
            continue

 host指服務器ip

port指服務器端口

使用with 語句創建socket對象

s.connect進行tcp連接

s.settimeout(5)設置超時時間,如果一段5秒以後沒有還是沒有和服務器進行正常的通信,那麼,就拋出socket.timeout異常

接下來進行死循環,我們使用input發送我們想發送的字符串

然後使用sendall進行發送,發送之前使用encode將字符串轉爲bytes格式

接下來進行recv,接收服務器返回來的數據

打印輸入服務器數據

如果我們捕獲了socket.timeout異常,則進行下一次的數據發送

下圖爲客戶端程序輸出:

下圖爲服務端程序輸出:

至此,簡單的tcp程序就完成了

 

  • 總結

有了上面的程序,再進行一點異常的捕獲、優化,我們就能夠進行相對穩定的tcp連接了, 如果後面有碰到多連接的情況,再進行處理。

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