Python SSL 套接字服务器

3 投票
2 回答
7557 浏览
提问于 2025-04-17 09:43

我想搭建一个基本的SSL认证的套接字服务器,用来进行网络通信。但是我遇到了下面的错误。看起来是因为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()

我用以下命令创建了密钥文件和证书:

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

2 个回答

0

pems?这不是应该是 pem 吗?

    ca_certs="fake_auth/server_certfile.pems",

你把它弄好了没有?

3

Tornado可以自己处理SSL连接,只要你使用的是Python 2.6及以上版本和OpenSSL。那你为什么还要手动去建立SSL的套接字连接呢?

可以查看这个链接了解更多信息:http://www.tornadoweb.org/documentation/httpserver.html#http-server

重点说明:

HTTPServer可以在Python 2.6及以上版本和OpenSSL的支持下处理SSL流量。要让这个服务器支持SSL流量,你需要发送一个叫做ssl_options的字典,里面包含ssl.wrap_socket方法所需的参数,比如“certfile”(证书文件)和“keyfile”(密钥文件):

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

撰写回答