Рубрики

Создание прокси-сервера в Python | Комплект 1

Сокетное программирование на python очень удобно для пользователя по сравнению с c. Программисту не нужно беспокоиться о мелочах, касающихся сокетов. В python у пользователя больше шансов сосредоточиться на прикладном уровне, а не на сетевом уровне. В этом уроке мы будем разрабатывать простой многопоточный прокси-сервер, способный обрабатывать HTTP-трафик. Это будет в основном основано на основных идеях программирования сокетов. Если вы не уверены в основах, я бы порекомендовал почистить их перед тем, как пройти этот урок.

Это наивная реализация прокси-сервера. Мы будем постепенно превращать его в довольно полезный сервер в следующих уроках.

Начнем с того, что мы выполним процесс в 3 простых шага

1. Создание входящего сокета
Мы создаем сокет serverSocket в методе __init__ класса сервера. Это создает сокет для входящих соединений. Затем мы связываем сокет и затем ожидаем подключения клиентов.

def __init__(self, config):
    # Shutdown on Ctrl+C
    signal.signal(signal.SIGINT, self.shutdown) 

    # Create a TCP socket
    self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Re-use the socket
    self.serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # bind the socket to a public host, and a port   
    self.serverSocket.bind((config['HOST_NAME'], config['BIND_PORT']))
    
    self.serverSocket.listen(10) # become a server socket
    self.__clients = {}

2. Принять клиента и процесс
Это самый простой, но самый важный из всех шагов. Мы ожидаем запроса клиента на подключение и, как только успешное соединение установлено, мы отправляем запрос в отдельном потоке, делая себя доступными для следующего запроса. Это позволяет нам обрабатывать несколько запросов одновременно, что повышает производительность сервера в разы.

while True:

    # Establish the connection
    (clientSocket, client_address) = self.serverSocket.accept() 
    
    d = threading.Thread(name=self._getClientName(client_address), 
    target = self.proxy_thread, args=(clientSocket, client_address))
    d.setDaemon(True)
    d.start()

3. Перенаправление трафика
Основная функция прокси-сервера заключается в том, чтобы выступать в качестве промежуточного звена между источником и назначением. Здесь мы будем получать данные из источника и затем передавать их клиенту.

  • Сначала мы извлекаем URL из полученных данных запроса.
# get the request from browser
request = conn.recv(config['MAX_REQUEST_LEN']) 

# parse the first line
first_line = request.split('\n')[0]

# get url
url = first_line.split(' ')[1]
  • Затем мы находим адрес назначения запроса. Адрес — это кортеж из (destination_ip_address, destination_port_no) . Мы будем получать данные с этого адреса.
http_pos = url.find("://") # find pos of ://
if (http_pos==-1):
    temp = url
else:
    temp = url[(http_pos+3):] # get the rest of url

port_pos = temp.find(":") # find the port pos (if any)

# find end of web server
webserver_pos = temp.find("/")
if webserver_pos == -1:
    webserver_pos = len(temp)

webserver = ""
port = -1
if (port_pos==-1 or webserver_pos < port_pos): 

    # default port 
    port = 80 
    webserver = temp[:webserver_pos] 

else: # specific port 
    port = int((temp[(port_pos+1):])[:webserver_pos-port_pos-1])
    webserver = temp[:port_pos] 
  • Теперь мы устанавливаем новое соединение с конечным сервером (или удаленным сервером), а затем отправляем копию исходного запроса на сервер. Затем сервер ответит ответом. Все ответные сообщения используют общий формат сообщения RFC 822 .
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.settimeout(config['CONNECTION_TIMEOUT'])
s.connect((webserver, port))
s.sendall(request)
  • Затем мы перенаправляем ответ сервера клиенту. conn — это исходное соединение с клиентом. Ответ может быть больше, чем MAX_REQUEST_LEN, который мы получаем за один вызов, поэтому нулевой ответ отмечает конец ответа.
while 1:
    # receive data from web server
    data = s.recv(config['MAX_REQUEST_LEN'])

    if (len(data) > 0):
        conn.send(data) # send to browser/client
    else:
        break

Затем мы соответствующим образом закрываем соединения с сервером и выполняем обработку ошибок, чтобы убедиться, что сервер работает должным образом.

Как проверить сервер?
1. Запустите сервер на терминале. Оставьте его включенным и переключитесь на ваш любимый браузер.
2. Зайдите в настройки прокси вашего браузера и измените прокси-сервер на «localhost» и порт на «12345».
3. Теперь откройте любой HTTP-сайт (не HTTPS), например. geeksforgeeks.org и volla !! Вы должны иметь доступ к содержимому в браузере.

Когда сервер запущен, мы можем отслеживать запросы, поступающие к клиенту. Мы можем использовать эти данные для мониторинга контента, который мы собираемся, или мы можем разрабатывать статистику на основе контента.
Мы даже можем ограничить доступ к веб-сайту или занести в черный список IP-адрес. Мы будем иметь дело с большим количеством таких функций в следующих уроках.
Что дальше?
Мы добавим следующие функции в наш прокси-сервер в следующих уроках.
— Черные списки доменов
— Контентный мониторинг
— Логирование
— HTTP WebServer + ProxyServer

Весь рабочий исходный код этого руководства доступен здесь.

Создание прокси-сервера в Python | Набор 2

Если у вас есть какие-либо вопросы / комментарии, не стесняйтесь размещать их в разделе комментариев.

Об авторе:

Пинкеш Баджатия родом из IIIT Хайдарабада. Он — вундеркинд с множеством проектов, достойных внимания. Его проектную работу можно увидеть здесь.

Если вы также хотите продемонстрировать свой блог здесь, пожалуйста, смотрите GBlog для записи гостевого блога на GeeksforGeeks.

Рекомендуемые посты:

Создание прокси-сервера в Python | Комплект 1

0.00 (0%) 0 votes