2018年7月12日 星期四

一起學 Python 111 : 使用 Python 架設可由外部網路連入的 TCP Server

呈之前的兩篇

1. 一起學 Python 105 : 接收與傳送 TCP/IP (Client 連至 Server) 並將接收到的值傳到 google sheet
2. 一起學 Python 110 : 外部網路連回家中網路 遠端操控 Raspberry pi (使用 No-ip )

第一篇完成了內部網路的 電腦(client) 與手 機(server) 的TCP通訊
第二篇說明了如何使用 No-ip 讓手機可以連入家中的區域網路

連到分享器裡面去設定虛擬伺服器使外部網路可以藉由 no-ip網域名稱及對外port 連結到家中網路並經由對內 port 連接到 PC,那邊我就不再解釋了(請見上方 2 文),總之我隨便設定了一個 port ,對外對內皆為 41210 並且綁定到電腦的固定區域網路 ip ( ex: 192.168.0.102 , 見 2 文)

接著使用以下 Python 程式碼搭建 TCP Server

import socket, sys 
import threading 

# 此程式碼修改自
# http://hhtucode.blogspot.com/2013/03/python-simple-socket-server.html

port = 41210

# 多線程
# 叫一個 thread 接收 client 端所傳過來的內容, 再傳回去
# 使用多線程可讓server 端還是可以不停的接收新進的client繼續工作
# 既不會影響 client 又可以保持 server 流暢
def threadWork(client):
    while True:
        msg = client.recv(1024).decode(encoding='utf_8', errors='strict')
        if not msg:
            pass
        else:
            print("Client send: %s" % msg )
            text = "You say: " +  msg + "\r\n"
            client.send(text.encode(encoding='utf_8', errors='strict'))
    client.close()

try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as msg:
    sys.stderr.write("[ERROR] %s\n" % msg[1])
    sys.exit(1)

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind( ('', port) )
sock.listen(5)#最多可以讓幾個連線數

while True:
    print("Listening ... ")
    (csock, adr) = sock.accept()    
    #啟動server準備讓client傳送訊息
    #使用accept()的時候, server會處在wait狀態, 等到有client連線的時候
    #會將整個連線跟client資訊回傳出來
    #clientsocket就是存放這次的連線, 之後可以透過clientsocket來跟client做其他溝通
    #address就會有連過來IP/PORT相關資訊
    #收到的客戶端連線叫做csock, 所以如果你要收或者是傳對方的訊息記得要用 csock
    
    print("Client Info: " , csock , adr )
    thread = threading.Thread(target=threadWork,args=(csock,))   # 設定線程
    thread.start()# 啟動線程

sock.close()


成功開啟 Server 後用手機下載 App ' TCP Client ' , ip 設定為 no-ip網域名稱 wyj.hopto.org;port 設定為 41210

為了測試,我把電腦連回我家中的網路

Hint:此文中我的電腦並沒有下載 noip 的程式(也就是duc)常駐在我的電腦上,因為在我家中的網域中已經有使用 raspberry pi 常駐這個程式。若你並沒有這樣子做,那你應該在你的電腦裝上 noip 的 duc 程式並常駐,以便 noip 的網域名稱抓取你的實體ip

手機成功連線後試著發送訊息,當電腦的 Server 收到訊息後會回傳訊息


電腦 Server 端




手機 Client 端






參考連結
[Python] Simple Socket Server
[ Python 文章收集 ] Python模塊學習 - threading 多線程控制和處理Python初學——多執行緒Threading
添加线程 Thread
Python初學——多執行緒Threading