【问题标题】:Python SSL Socket: receiving and sending from both server and clientPython SSL Socket:从服务器和客户端接收和发送
【发布时间】:2012-12-10 23:36:23
【问题描述】:

好的,所以我正在尝试通过 SSL 套接字连接在服务器和客户端之间进行来回通信。我认为最好的方法是在每个线程中实现 2 个线程,每个线程分别充当服务器和客户端。但是当我实现此代码时(显然在其他服务器/客户端中使用相反的相应端口) :

#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')

请帮助我 StackOverFlow,你是我唯一的希望。我知道这应该很容易,但此时我的大脑非常紧张,我无法再思考了。

另外,我对 python 还很陌生,所以很有可能它的操作/加载类/等的方式有些东西,我只是不明白。

编辑:好的,我知道这段代码很糟糕。它不是要上市的产品,它永远不会实时运行,这只是我试图让一个概念起作用,这个概念是:让服务器和客户端通过 python ssl 连接相互发送消息。

我知道这是很糟糕的代码,但我只需要知道如何让服务器发回消息,因为每当我尝试它时,最后都会收到错误。

【问题讨论】:

  • 为什么需要两个socket?套接字是双向的;您无需单独从服务器连接回客户端以发送数据。 (而且您可能不希望这样做,因为 Internet 上的许多客户端都位于 NAT 之后,并且无法通过这种方式直接访问。)您的设计中是否有某些东西使您没有解释这一点?跨度>
  • 原来有一些我想专门与(从服务器)交谈的客户,但我现在意识到我不需要那个。然后我试图让服务器发回数据,但是就像它说的那样,我找不到使用套接字的 SSL 方法,它一直给我一个错误。
  • 同时,您得到的错误是告诉您没有人在监听端口 12345。您确定客户端此时实际上正在尝试监听吗?查看您的代码,如果双方都在做“以一种方式做所有事情,然后休眠 6 秒,然后以另一种方式做所有事情”,那么服务器会在客户端开始侦听之前尝试连接是完全合理的......
  • 好吧,我假设它自己的线程中的while True: 会在另一个线程运行时继续运行。那个和这个同时运行的另一个版本的事实是相反的,可以说,在端口 12345 上设置服务器并等待连接,然后尝试在 5570 上发送。

标签: python sockets ssl client


【解决方案1】:

您的设计似乎在很多层面都被误导了。

首先,双向发送数据不需要两个套接字;套接字是双向的。

而且您可能不想要建立从服务器到客户端的连接 - 这可能在 localhost 测试中有效,但是一旦您部署到互联网,大多数客户端将落后NAT 路由器,并且没有您可以连接的公共地址。

同时,你的逻辑很奇怪。您在一个方向上开始连接,然后休眠 6 秒,然后在另一个方向上开始连接。为什么要这样做?

如果服务器之前调用它的SecureOut,或者甚至在同一时间调用它的SecureIn,它会在有人监听之前尝试连接,这将得到你所看到的错误。

另外,每个线程都有一个非常奇怪的运行循环:

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 上工作,并且对于这么小的消息,它可能会在互联网上大部分工作,但不是所有时间。 p>

您似乎也对类变量和实例变量之间的区别感到困惑,因为您在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 化。

【讨论】:

  • A) 这都是为了测试目的。就像我说的,我是新手,它永远不会在 localhost 以外的任何地方运行。 B)出于测试的目的,我希望服务器继续无限接受。 C) 完成了所有的教程,完成了所有的发送和接收,可以让这一切正常工作,但我唯一需要的就是我找不到任何地方是服务器通过 SSL 套接字发送的一种方式。跨度>
  • 好吧,如果我只是问一个简单的问题,因为这不是要部署的,这只是我试图让一个新概念发挥作用,它不专业,永远不会部署。所以直截了当的问题是,如何让服务器在 python 中发送 SSL 套接字,而不会收到最后一条错误消息(来自不同的代码块)?
  • 该错误消息不是来自send,而是来自connect。您可以看出这是因为它是“连接被拒绝”,并且因为回溯显示行 s.connect(('localhost', 12345))。所以你的问题不是如何send 关闭一个套接字,而是首先如何连接套接字。它不起作用的原因几乎可以肯定是因为没有人在端口 12345 上侦听,大概是因为客户端尚未在该套接字上完成其 bindlisten。由于您只向我们展示了一半的代码,而不是问题的一半,我所能做的就是猜猜为什么,所以我做了。
  • @user1585054:同时,您知道如何使用http://en.wikipedia.org/wiki/Netcathttp://en.wikipedia.org/wiki/Nmap 或其他工具来测试套接字代码吗?您可以验证是否有人正在监听 localhost:12345,甚至可以同时使用 netcatopenssl 连接到端口 12345 上的任何内容并发送数据并确保其正常工作。
  • 我参考了第二个错误,即无法从服务器通过 ssl 套接字进行发送。最后一个错误来自我更新问题的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
  • 2011-05-12
  • 1970-01-01
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多