Python SSL 套接字服务器

标签 python sockets ssl tornado

我想设置一个基本的 ssl-authenticated 套接字服务器来进行一些网络通信。我收到以下错误。它似乎来自 SSLIOStream 而不是阅读前的握手:

  File "simple_ssl_server.py", line 70, in connection_ready
    node_io_stream.read_until("OK", on_ok)
  File "/home/tombrown/skyhook/lib/python2.7/site-packages/tornado-2.1.1-py2.7.egg/tornado/iostream.py", line 161, in read_until
    if self._read_to_buffer() == 0:
  File "/home/tombrown/skyhook/lib/python2.7/site-packages/tornado-2.1.1-py2.7.egg/tornado/iostream.py", line 375, in _read_to_buffer
    chunk = self._read_from_socket()
  File "/home/tombrown/skyhook/lib/python2.7/site-packages/tornado-2.1.1-py2.7.egg/tornado/iostream.py", line 635, in _read_from_socket
    chunk = self.socket.read(self.read_chunk_size)
  File "/usr/lib/python2.7/ssl.py", line 151, in read
    return self._sslobj.read(len)
SSLError: [Errno 1] _ssl.c:1354: error:1408F044:SSL routines:SSL3_GET_RECORD:internal error

这是我的服务器代码:

import tornado.web
import tornado.httpserver
import select
import socket
import tornado.iostream
import random
import logging
import ssl
import functools


class SSLSocketServer(object):

    def __init__(self, io_loop=None, config_file=None, debug=False):
        if io_loop is None: io_loop = tornado.ioloop.IOLoop.instance()

        # Set up our node-accepting socket on port 8013
        HOST = ''                 # Symbolic name meaning all available interfaces
        PORT = 8013               # Arbitrary non-privileged port

        server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_sock.setblocking(0)

        server_sock.bind((HOST, PORT))
        # We allow a backlog of up to 128 pending connections.
        server_sock.listen(128)

        callback = functools.partial(self.connection_ready, server_sock)
        io_loop.add_handler(server_sock.fileno(),
            callback, io_loop.READ)

    def connection_ready(self, sock, fd, events):
        # In part from: https://github.com/saucelabs/monocle/blob/7bd978f1c6a2ad3d78dd3da0b5b73c3e215ebbf3/monocle/tornado_stack/network/__init__.py
        while True:

            # Wait for the basic socket to be available.
            try:
                node_sock, address = sock.accept()
            except socket.error, e:
                if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
                    raise
                return

            # Wait for the ssl socket to be available.
            try:
                node_sock = ssl.wrap_socket(node_sock,
                            do_handshake_on_connect=False,
                            server_side=True,
                            certfile="cert.pem",
                            ssl_version=ssl.PROTOCOL_TLSv1)
            except ssl.SSLError, err:
                if err.args[0] == ssl.SSL_ERROR_EOF:
                    s.close()
                    return
                else:
                    raise
            except socket.error, err:
                if err.args[0] == errno.ECONNABORTED:
                    s.close()
                    return
                else:
                    raise

            node_io_stream = tornado.iostream.SSLIOStream(node_sock)

            def on_ok():
                print "recieved OK!"
            node_io_stream.read_until("OK", on_ok)


if __name__ == '__main__':
    # Get a handle to the instance of IOLoop
    io_loop = tornado.ioloop.IOLoop.instance()
    worker = SSLSocketServer(io_loop)
    # Start the IOLoop
    io_loop.start()

这是客户端代码:

import sys
import logging
import socket
from tornado import iostream
from tornado import ioloop
import uuid
from tornado.options import define, options
import json
import ssl


def main():

    delim = '\r\n\r\n'

    def send_request():
        print "sending OK"
        stream.write("OK")

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)

    # stream = iostream.IOStream(s)
    stream = iostream.SSLIOStream(s, 
        ssl_options= dict(
            ca_certs="fake_auth/server_certfile.pems",
            cert_reqs=ssl.CERT_NONE))

    print "about to connect"
    stream.connect(('', 8013), send_request)

    ioloop.IOLoop.instance().start()


if __name__ == '__main__':
    main()

我使用以下命令创建了 key 文件和证书:

openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem

最佳答案

Tornado 能够使用 python 2.6+ 和 OpenSSL 自行维护 SSL 连接。为什么要尝试手动构建 SSL 套接字连接?

checkout :http://www.tornadoweb.org/documentation/httpserver.html#http-server

关键标题:

HTTPServer can serve SSL traffic with Python 2.6+ and OpenSSL. To make this server serve SSL traffic, send the ssl_options dictionary argument with the arguments required for the ssl.wrap_socket method, including “certfile” and “keyfile”:

HTTPServer(applicaton, ssl_options={
    "certfile": os.path.join(data_dir, "mydomain.crt"),
    "keyfile": os.path.join(data_dir, "mydomain.key"),
})

关于Python SSL 套接字服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8767757/

相关文章:

sockets - HAProxy 套接字 API "get acl"错误 : "Missing ACL identifier and/or key"

ssl - 在 AWS Elastic Beanstalk 上安装通配符 SSL 证书

python - 使用参数 'LIKE' 搜索日期

python - 如何添加两个嵌套的Python字典?

c++ - 哪种协议(protocol)用于通过 LAN 开发聊天应用程序?

java - 如何从线程中运行的循环中获取字符串?

google-app-engine - 使用 Google Domains 和 Google Bucket 进行静态托管时如何安装 SSL?

css - 由于 CSS 背景图像,SSL 和混合内容

Python - 如何在 AWS Lambda 中优雅地处理超时

python - fnmatch 不适用于变量,但适用于静态字符串