2017-04-12 90 views
0

對於套接字編程和線程的總體來說,這是一個新興的問題,我的問題可能是由於誤解了它們的工作原理。我正在嘗試使用線程來創建充當客戶端和服務器的東西。永遠在後臺運行python線程化的TCP服務器

以下: https://docs.python.org/3/library/socketserver.html#asynchronous-mixins

我創建了一個客戶端類去與服務器無論從主類執行。服務器通常理應啓動並沒有給出任何錯誤,但是當我嘗試從客戶端連接,它在以下失敗:

# In client connection 
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    sock.connect((ip, port)) 

我得到的錯誤是:

Traceback (most recent call last): 
    File "./<project>", line 61, in <module> 
    client.start_client(serverInfo) 
    File "/home/<username>/Documents/Github/project/client.py", line 54, in <startclient> 
    <connectionMethod>(cmd) 
    File "/home/<username>/Documents/Github/project/client.py", line 112, in <connectionMethod> 
    sock.connect((remoteHOST,remotePORT)) 
    ConnectionRefusedError: [Errno 111] Connection refused 

即使當我修改服務器從代碼中所引用的蟒蛇頁面(只是爲了一個特定的端口,1234上運行),並嘗試以

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: 
    sock.connect(('127.0.0.1',1234)) 
    sock.sendall('Test message') 

我得到了同樣的問題連接到該端口

Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
ConnectionRefusedError: [Errno 111] Connection refused 

爲什麼服務器拒絕連接?沒有防火牆規則或iptables的地方,運行的例子有客戶端和套接字一起從網站工作,但即使刪除server.shutdown()線,它仍然立即自殺。

我錯過了什麼嗎?

我期待的行爲是:

./programA 
<server starts on port 30000> 

./programB 
<server starts on port 30001> 
<client starts> 

---輸入/輸出---

從客戶答:

/connect 127.0.0.1 30001 
CONNECTED TO 127.0.0.1 30001 

ON客戶B:

CONNECTION FROM 127.0.0.1 30000 

基本上一旦客戶端連接在第一時間,他們可以通過鍵入到提示,這只是創建另一個插座靶向「遠程」 IP和端口發送關閉消息(即時通訊)彼此通信。因爲他們實際上不負責接收任何事情,所以套接字是剩餘的關閉。

我會很感激任何幫助,我可以得到這一點。

+0

你既可以使每個客戶端也是一個服務器,或者讓主服務器手柄通過指定客戶端標識符 –

+0

@ t.m.adam所有連接自己講法不當,但每個客戶_was_也是一個服務器。本質上,客戶端提示符是一個類,線程服務器是一個類。這個問題來自python文檔中給出的threadedPSPServer socketserver示例。實際上,這聽起來可能並不適用於超時。我設法通過使用標準套接字和綁定來解決我的問題。我不確定是否在socketserver中沒有使用「ThreadingMixIn」或它們的特定版本有任何問題,但到目前爲止我還沒遇到任何問題。我現在將標記我的解決方案,因爲它似乎工作。 – user2763113

回答

0

順便說一句,我已經取得了突破性的東西。雖然我不能完全肯定爲什麼它這樣做,threadedTCPServer(因爲它是Python文檔)是基本上不能用於此目的,實際上在一個線程不會採取行動的權利,同時。相反,我選擇了手工創建一個套接字服務器,像這樣:

import threading 
import socket 

def simpleServer(): 
    HOST = '127.0.0.1' 
    PORT = 3000 
    sock = socket.socket() 
    sock.bind((HOST,PORT)) 

    s.listen(5) 
    while True: 
     conn, addr = s.accept() 
     msg = str(conn.recv(1024),'utf8') 
     c.send(bytes('GOT: {0}'.format(msg),'utf8') 
     c.close() 

if __name__ == '__main__': 

    server_thread = threading.Thread(target=simpleServer) 
    server_thread.start() 

    # Make connections based on '<ip>:<port>:<msg>' 
    while True: 
     cmd = input('>> ') 

     try: 
      parts = cmd.split(':') 
      ip = parts[0] 
      port = parts[1] 
      msg = parts[2] 

      with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: 
       sock.connect((ip,port)) 
       sock.sendall(bytes(msg,'utf8')) 
       print(str(sock.recv(1024),'utf8')) 

     except Exception as e: 
      print(e) 

的代碼是非常基本的(也可能不是最好的),但我剛剛測試,它絕對是現在的工作。我根據我看到的解決方案改編了這段代碼:Why am I getting the error "connection refused" in Python? (Sockets)

我必須重新調整大部分代碼,但我認爲它應該可以正常工作,我會在執行後報告。

0


之所以甚至消除server.shutdown()是沒有幫助,因爲當主線程存在,服務器線程,因爲你可能還沒有刪除server_thread.daemon=True立刻存在。
如果將其更改爲server_thread.daemon=False,那麼即使在主線程終止後,程序也不會立即返回到終端,但即使主程序的最後一行執行後,也不會終止服務器。
我不知道你是否可以使用簡單的Python腳本完全在後臺運行服務器,但我認爲這是不可能的。

你可以用'&'選項調用腳本:python3 <file>.py &它將在後臺運行python腳本(至少與Ubuntu一起工作)(https://askubuntu.com/questions/396654/how-to-run-the-python-program-in-the-background-in-ubuntu-machine),但它可能不是你正在尋找的答案。

+0

是不是我所希望的。本質上它是一個即時通訊程序,我已經看到了,但我不太確定他們是如何讓客戶端成爲唯一必須開始的事情,而不是讓每個客戶端也成爲服務器。程序的服務器部分負責收集和存儲對操作至關重要的信息。 – user2763113

+0

我也嘗試刪除守護線(我忘了提到它),結果是服務器「熬夜」,但仍無法連接到。對於線程,我認爲儘管理論上它應該是可能的,因爲服務器將在其自己的線程上執行,而客戶端在另一個線程上執行。 – user2763113