2017-04-10 47 views
0

我有一個小問題。 我是新來的整個套接字理論和龍捲風框架。最近我寫了一個使用Tornado框架的代理服務器。我的應用程序站在連接客戶端(瀏覽器)< ===>遠程地址的中間。因此,連接看起來是這樣的:如果我使用標準「主要」功能通過套接字服務代理應用程序Tornado 4.4

client(my web browser) <=== PROXY(my app) ===> Remote address (stackoverflow.com)

,一切工作正常。但我想要更低層次,我的意思是我想創建套接字並通過該連接提供我的代理應用程序。

我代理的應用程序網址:

# coding: utf-8 
"""URL's for proxy app.""" 
from settings import settings 
from tornado.web import (
    StaticFileHandler, 
    url, 
) 
from handlers import (
    mainHandlers, 
    myProxy, 
) 

urls = [ 
    url(r"/admin/$", mainHandlers.MainHandler), 
    url(r"/admin/delete_filter/", mainHandlers.DataDeleteHandler), 
    url(r"/admin/filters/$", mainHandlers.DataGetter), 
    url(r"/admin/new_filter/$", mainHandlers.FormHandler), 
    url(r"/admin/stats/$", mainHandlers.StatsTableHandler), 
    url(r"/admin/stats/query/$", mainHandlers.AjaxStatsGetHandler), 
    url(r"/static/", StaticFileHandler, dict(path=settings['static_path'])), 

    url(r'.*', myProxy.ProxyHandler), 
    ] 

我ProxyHandler:

class ProxyHandler(tornado.web.RequestHandler): 

    SUPPORTED_METHODS = ['GET', 'POST'] 

    def data_received(self, chunk): 
     pass 

    def compute_etag(self): 
     return None # disable tornado Etag 

    def handle_response(self, response): 
     if response.error and not isinstance(response.error, tornado.httpclient.HTTPError): 
      self.set_status(500) 
      self.write('Internal server error:\n' + str(response.error)) 
     else: 
      self.set_status(response.code, response.reason) 
      self._headers = tornado.httputil.HTTPHeaders() # clear tornado default header 

      for header, v in response.headers.get_all(): 
       if header not in ('Content-Length', 'Transfer-Encoding', 'Content-Encoding', 'Connection'): 
        self.add_header(header, v) # some header appear multiple times, eg 'Set-Cookie' 

      secured_page = False 
      for page in secure_pages: 
       if page in self.request.uri: 
        secured_page = True 
        self.set_header('Content-Length', len(response.body)) 
        self.write(response.body) 
        break 
      if response.body and not secured_page: 
       c.execute('SELECT filter_name FROM filters WHERE filter_type=1') 
       tags = c.fetchall() 
       soup = BeautifulSoup(response.body, 'html.parser') 
       for row in tags: 
        catched_tags = soup.find_all(str(row[0])) 
        if catched_tags: 
         print 'catched: %s of <%s> tags' % (len(catched_tags), str(row[0])) 
        for tag in catched_tags: 
         tag.extract() 
       new_body = str(soup) 
       self.set_header('Content-Length', len(new_body)) 
       self.write(new_body) 
     self.finish() 

    @tornado.web.asynchronous 
    def get(self): 
     logger.debug('Handle %s request to %s', self.request.method, self.request.uri) 

     body = self.request.body 
     if not body: 
      body = None 

     try: 
      if 'Proxy-Connection' in self.request.headers: 
       del self.request.headers['Proxy-Connection'] 

      c.execute('SELECT filter_name FROM filters WHERE filter_type=2') 
      urls = c.fetchall() 
      for url in urls: 
       if url[0] in self.request.path: 
        self.set_status(403) 
        self.finish() 
        return 

      fetch_request(self.request.uri, self.handle_response, 
         method=self.request.method, body=body, headers=self.request.headers, follow_redirects=False, 
         allow_nonstandard_methods=True) 
     except tornado.httpclient.HTTPError as e: 
      if hasattr(e, 'response') and e.response: 
       self.handle_response(e.response) 
      else: 
       self.set_status(500) 
       self.write('Internal server error:\n' + str(e)) 
       self.finish() 

    @tornado.web.asynchronous 
    def post(self): 
     return self.get() 

最簡單的主要功能:

# coding: utf-8 
import sys 
import tornado.web 
from tornado.options import options 
from configuration.application import MyApplication 
from proxy.urls import proxy_urls 

def make_app(): 
    """Create my application with my settings and urls.""" 
    return MyApplication(proxy_urls) 


if __name__ == "__main__": 
    u"""Main loop.""" 

    app = make_app() 
    port = options.port 
    if len(sys.argv) > 1: 
     port = int(sys.argv[1]) 
    app.listen(port) 
    print 'tornado working on port %s' % port 
    tornado.ioloop.IOLoop.current().start() 

所以我想最簡單的方式改變爲低基於文檔的高級方式:

import errno 
import functools 
import tornado.ioloop 
import socket 

def connection_ready(sock, fd, events): 
    while True: 
     try: 
      connection, address = sock.accept() 
     except socket.error as e: 
      if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN): 
       raise 
      return 
     connection.setblocking(0) 
     handle_connection(connection, address) 

if __name__ == '__main__': 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    sock.setblocking(0) 
    sock.bind(("", port)) 
    sock.listen(128) 

    io_loop = tornado.ioloop.IOLoop.current() 
    callback = functools.partial(connection_ready, sock) 
    io_loop.add_handler(sock.fileno(), callback, io_loop.READ) 
    io_loop.start() 

爲了做到這一點,我讀了一些關於使用套接字的整個網絡編程(https://www.tutorialspoint.com/python/python_networking.htm)。 本教程中的例子效果很好,所以我試圖教程與龍捲風文檔的例子連接:

# coding: utf-8 
import errno 
import functools 
import socket 
import sys 
import tornado.httpserver 
import tornado.ioloop 
import tornado.netutil 
import tornado.process 
import tornado.web 
from tornado.options import options 
from configuration.application import MyApplication 

def make_app(): 
    u"""Create my application with my settings and urls.""" 
    return MyApplication() 

def connection_ready(sock, fd, events): 
    u"""Function to handle an incoming connection.""" 
    proxy_app = make_app() 
    server = tornado.httpserver.HTTPServer(proxy_app) 
    while True: 
     try: 
      connection, address = sock.accept() 
     except socket.error as e: 
      if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN): 
       raise 
      return 
     print 'Got connection from', address 
     # connection.setblocking(False) 
     connection.send(server) 
     connection.close() 

if __name__ == "__main__": 
    u"""Main loop.""" 

    port = options.port 
    if len(sys.argv) > 1: 
     port = int(sys.argv[1]) 

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    sock.setblocking(False) 
    sock.bind(('', port)) 
    sock.listen(5) 

    io_loop = tornado.ioloop.IOLoop.current() 
    callback = functools.partial(connection_ready, sock) 
    io_loop.add_handler(sock.fileno(), callback, io_loop.READ) 
    print 'Tornado Proxy working on port: %s' % port 
    io_loop.start() 

但是,當我嘗試連接到我的代理服務器(例如添加過濾器:http://127.0.0.1:8000/admin/filters/ - 我有 寫入處理這個網址的處理程序),我得到specyfic錯誤:

ERROR:tornado.application:Exception in callback (3,)

Traceback (most recent call last):

File "/home/dave/.virtualenvs/teleV1/local/lib/python2.7/site-packages/tornado/ioloop.py", line 887, in start handler_func(fd_obj, events)

File "/home/dave/.virtualenvs/teleV1/local/lib/python2.7/site-packages/tornado/stack_context.py", line 275, in null_wrapper return fn(*args, **kwargs)

File "manage.py", line 35, in connection_ready connection.send(server)

TypeError: send() argument 1 must be convertible to a buffer, not HTTPServer

我明白,我無法通過連接(從一端到另一發送的HttpServer),它必須是一個緩衝。 我的第一個想法是從處理URL(例如類ProxyHandler(tornado.web.RequestHandler)), 的處理程序發送buffor,但是如何處理不同的url和不同的處理程序?

回答

0

經過一些方法之後,我將我的代理應用程序更改爲一個純Python代碼,該代碼處理來自遠程地址的響應並執行過濾。我認爲這是我能做的最好最快的事情。

相關問題