3

OK、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にかなり慣れていないので、クラスなどを操作/ロードする方法について、私が理解できない何かがある可能性が非常に高いです。

編集:OK、このコードが悪いことはわかっています。これは市場に出回る製品ではなく、ライブで実行されることはありません。これは私がコンセプトを機能させようとしているだけであり、そのコンセプトは、サーバーとクライアントがpython ssl接続を介して互いにメッセージを送信することです.

これがひどいコードであることはわかっていますが、サーバーにメッセージを送り返す方法を知る必要があるだけです。これを試みるたびに最後にエラーが発生するからです。

4

1 に答える 1

4

あなたのデザインは多くのレベルで見当違いのようです。

まず、双方向にデータを送信するために 2 つのソケットは必要ありません。ソケットは双方向です。

また、サーバーからクライアントへの接続を作成したくない場合もあります。これは localhost のテストでは機能する可能性がありますが、インターネットに展開すると、ほとんどのクライアントは NAT ルーターの背後にあり、パブリック アドレスはありません。に接続できます。

一方、あなたの論理は非常に奇妙です。一方向で接続を開始し、6 秒間スリープしてから、反対方向で接続を開始します。なぜそれをしたいのですか?

SecureOutクライアントが を呼び出す前に、またはほぼ同時にサーバーが を呼び出すとSecureIn、誰かがリッスンする前に接続を試みます。これにより、表示されているエラーが正確に発生します。

また、スレッドごとに非常に奇妙な実行ループがあります。

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

これは、一度に 1 つの接続のみを受け入れ、そこから 1 回の読み取りを行い、接続をリークし、二度と通信せず、次のクライアントを取得します。(また、すでにリッスンしているソケットで再度呼び出すことが実際に有効listen(5)かどうか、またはそれが何をするかについてもわかりません。) そしてもちろん、それが終了する方法はありません。(これは正確ではありません。たとえば、クライアントが接続してから を呼び出す前に離れた場合recv、おそらく例外が発生しますが、それをキャッチしないため、プログラムは終了します…) それはあなたが望むものですか?

また、なぜrecv(5570)ですか?その数は、ポート番号ではなく、読み取る最大バイト数です。

そして、なぜrepr文字列の を出力するのでしょうか?

一方、recvバッファ長に何を渡しても、 はメッセージ全体を取得することが保証されていないことを認識していますか (または、複数のメッセージを送信したクライアントがあった場合は、2 つではなく 1 つのメッセージのみを取得します)。localhost で機能することはほぼ確実に機能し、このような小さなメッセージでは、インターネット上でほとんどの場合機能する可能性がありますが、常に機能するわけではありません。

SecureInと の両方で一連のクラス変数を設定しているため、クラス変数とインスタンス変数の違いについても混乱しているようですSecureOut。これは、クラスのインスタンスを 2 つ持つことができた場合、それらが同じ を共有することSSL.Contextなどを意味します。実際には 2 つのインスタンスを同時に持つ必要がない場合でも、テストのために、ほぼ確実に を作成する必要があります。古いインスタンスを使用し続けるのではなく、新しいソケットなどを作成する必要があります。したがって、これの代わりに:

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 化する方法について心配することをお勧めします。

于 2012-12-10T23:54:35.220 に答える