2012-12-10 125 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

相关问题