2012-12-10 126 views
3

好吧,所以我試圖通過SSL套接字連接在服務器和客戶端之間來回通信。我認爲最好的方法是實現兩個線程,每個線程分別充當服務器和客戶端。但是當我實現這個代碼時(顯然使用其他服務器/客戶端中相對應的端口) :Python SSL套接字:從服務器和客戶端接收和發送

#secserv.py 

import socket 
from OpenSSL import SSL 
import threading 
import time 

class SecureIn(threading.Thread): 
    context = SSL.Context(SSL.SSLv23_METHOD) 
    context.use_privatekey_file('key') 
    context.use_certificate_file('cert') 

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s = SSL.Connection(context, s) 
    s.bind(('', 5570)) 
    def run(self): 
    while True: 
     self.s.listen(5) 
     (connection, address) = self.s.accept() 
     print repr(connection.recv(5570)) 


class SecureOut(threading.Thread): 
    time.sleep(6) 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.connect(('localhost', 12345)) 
    sslSocket = socket.ssl(s) 
    print repr(sslSocket.server()) 
    print repr(sslSocket.issuer()) 
    def run(self): 
    sslSocket.write('Hello secure socket\n') 

    s.close() 


si = SecureIn() 
si.start() 
time.sleep(6) 
so = SecureOut() 
so.start() 

我得到這個錯誤:

Traceback (most recent call last): 
    File "secserv.py", line 25, in <module> 
    class SecureOut(threading.Thread): 
    File "secserv.py", line 28, in SecureOut 
    s.connect(('localhost', 12345)) 
    File "/usr/lib/python2.7/socket.py", line 224, in meth 
    return getattr(self._sock,name)(*args) 
socket.error: [Errno 111] Connection refused 

或者我試圖得到一個獨立的服務器,甚至發送廣播消息到所有客戶端。我搜索了高和低,但我似乎無法找到一個工作方式來使用SSL套接字,只有普通的套接字。當我嘗試要麼s.write()s.sendall()我得到這個錯誤:

Traceback (most recent call last): 
    File "secserv.py", line 19, in <module> 
    s.write('hello client\n') 
OpenSSL.SSL.Error: [('SSL routines', 'SSL_write', 'uninitialized')] 

從這個代碼:

import socket 
from OpenSSL import SSL 
context = SSL.Context(SSL.SSLv23_METHOD) 
context.use_privatekey_file('key') 
context.use_certificate_file('cert') 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s = SSL.Connection(context, s) 
s.bind(('', 12345)) 
while True: 
    s.listen(5) 
    (connection, address) = s.accept() 
    print repr(connection.recv(12345)) 
    #This could also be s.sendall() 
    s.write('hello client\n') 

請幫我計算器,你是我唯一的希望。我知道這應該很容易,但是我的大腦在這一點上很緊張,我再也想不到了。

另外,我對Python非常陌生,所以很有可能它有一些操作方式/加載類/ etc,我只是不明白。

編輯:好的,我知道這段代碼是壞的。它不是一個將要上市的產品,它永遠不會實時運行,這只是我試圖讓一個概念工作,而這個概念是:讓服務器和客戶端通過python ssl連接互相發送消息。

我知道這是可怕的代碼,但我只需要知道如何讓服務器發回消息,因爲每當我嘗試它時,我都會在最後得到錯誤。

+1

爲什麼你需要兩個插座?套接字是雙向的;您不需要從服務器向客戶端單獨建立連接以發送數據。 (你可能不想這樣做,因爲互聯網上的許多客戶端都是NAT後面的,無法以這種方式直接聯繫到。)你的設計中是否有某些東西使得你沒有解釋這一點? – abarnert

+0

原來那裏有一些客戶我想單獨與服務器通話,但是現在我意識到我不需要這樣做。 然後我試圖讓服務器發回數據,但就像它說的,我無法找到用套接字來實現這一點的SSL方式,它一直給我一個錯誤。 – user1585054

+0

與此同時,您收到的錯誤是告訴您沒有人在12345端口上收聽。您確定客戶端實際上是在嘗試聆聽嗎?看看你的代碼,如果雙方都在做「一切都是單向的,然後睡6秒,然後以其他方式完成所有事情」,服務器在客戶端開始收聽之前嘗試連接是完全合理的。 – abarnert

回答

4

您的設計似乎在許多層面上被誤導。

首先,您不需要兩個套接字在兩個方向上發送數據;套接字是雙向的。

而且你可能不希望使從服務器返回給客戶端,可能在本地主機測試工作的連接,但一旦你部署到互聯網,大部分客戶將是NAT路由器後面,將不會有您可以連接到的公共地址。

同時,你的邏輯很奇怪。你開始在一個方向的連接,然後睡6秒,然後開始在另一個方向的連接。你爲什麼想這麼做?

如果服務器在客戶端呼叫其SecureIn之前或甚至幾乎在同一時間調用其SecureOut,它將嘗試在任何人收聽之前進行連接,這會得到您所看到的錯誤。

而且,你得爲每個線程一個很奇怪的運行循環:

def run(self): 
    while True: 
     self.s.listen(5) 
     (connection, address) = self.s.accept() 
     print repr(connection.recv(5570)) 

此只接受一次一個連接,確實從一個單一的讀,然後就漏連接,從不說話再次,並得到下一個客戶端。(我也不確定實際上是否有效地在已經在監聽的套接字上調用listen(5),或者它是做什麼的。)當然,它不可能完成。 (這並不完全正確 - 如果客戶端連接並在您撥打recv之前就消失了,您可能會收到一個異常,您不會捕獲這些異常,所以您的程序將會退出...)這就是您想要的?

另外,爲什麼recv(5570)?該數字是要讀取的最大字節數,而不是端口號。

爲什麼要打印一個字符串的repr

與此同時,你是否意識到recv,無論你通過什麼緩衝區長度,都不能保證獲得一個完整的消息(或者只獲得一條消息而不是兩條消息,如果你有一個客戶端發送了更多的消息比一個)?它幾乎肯定會在localhost上工作,並且帶有這樣一個小消息,它可能會在互聯網上工作大部分,但不是全部是的時間。

您似乎也對類變量和實例變量之間的差異感到困惑,因爲您在SecureInSecureOut中設置了一堆類變量。這意味着如果你可以有兩個實例,他們會共享相同的SSL.Context等等。即使你不需要在現實生活中同時有兩個實例,爲了測試你幾乎肯定會創建一個新的實例,你會想要創建一個新的套接字等,而不是繼續使用舊的套接字。因此,而不是這樣的:

class SecureIn(threading.Thread): 
    context = SSL.Context(SSL.SSLv23_METHOD) 
    context.use_privatekey_file('key') 
    context.use_certificate_file('cert') 
    … 

這樣做:

class SecureIn(threading.Thread): 
    def __init__(self): 
    self.context = SSL.Context(SSL.SSLv23_METHOD) 
    self.context.use_privatekey_file('key') 
    self.context.use_certificate_file('cert') 
    … 

(或者你可以把在run方法,當然)。

基本上,這是不可能做到任何有用的,有或沒有SSL。我建議你退後一步,閱讀一些教程,然後寫一些適用於普通TCP套接字的東西,然後擔心如何對它進行SSL化。

+0

A)這些都是爲了測試目的。就像我說的,我是新來的,它永遠不會運行在localhost以外的任何地方。 B)爲了測試的目的,我希望服務器繼續無限接受。 C)完成所有的教程,完成所有的發送和接收,可以使所有這些工作正常,但我唯一需要的,我找不到任何地方是服務器通過SSL套接字發送的方式。 – user1585054

+0

好的,也許如果我只是問簡單的問題,因爲這並不意味着要部署,這只是我試圖讓一個新的概念工作,它不是專業的,它永遠不會被部署。 所以直接的問題是,我怎樣才能讓服務器在python中發送SSL套接字,而不會收到最後一條錯誤消息(來自不同的代碼塊)? – user1585054

+0

該錯誤消息不是來自'send',而是來自'connect'。你可以這樣說,因爲它是一個「連接被拒絕」,並且因爲回溯顯示了行's.connect(('localhost',12345))'。所以你的問題不是如何向套接字發送,而是首先如何連接套接字。它不工作的原因幾乎可以肯定是因爲沒有人在12345端口上進行監聽,可能是因爲客戶端還沒有在該套接字上執行「綁定」和「監聽」。既然你只向我們展示了一半的代碼,而不是問題的一半,我所能做的只是猜測爲什麼,所以我做了。 – abarnert

相關問題