Подтвердить что ты не робот

Почему абонент прерывает соединение?

Я участвую в создании Python-сетей, и я вспомнил, что назад, когда я учил себя поточно, я наткнулся на эту страницу, поэтому я скопировали скрипты, обновили их для Python 3.1.1 и запустили их. Они отлично работали.

Затем я сделал несколько изменений. Моя цель - сделать что-то простое:

  • Клиент распиливает целое число и отправляет его на сервер.
  • Сервер получает маринованное целое число, распаковывает его, удваивает, затем рассосывает и отправляет обратно клиенту.
  • Клиент получает маринованное (и удвоенное) целое число, распаковывает его и выводит.

Здесь сервер:

import pickle
import socket
import threading

class ClientThread(threading.Thread):
    def __init__(self, channel, details):
        self.channel = channel
        self.details = details
        threading.Thread.__init__ ( self )

    def run(self):
        print('Received connection:', self.details[0])
        request = self.channel.recv(1024)
        response = pickle.dumps(pickle.loads(request) * 2)
        self.channel.send(response)
        self.channel.close()
        print('Closed connection:', self.details [ 0 ])

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 2727))
server.listen(5)

while True:
    channel, details = server.accept()
    ClientThread(channel, details).start()

И вот клиент:

import pickle
import socket
import threading

class ConnectionThread(threading.Thread):
    def run(self):
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect(('localhost', 2727))

        for x in range(10):
            client.send(pickle.dumps(x))
            print('Sent:',str(x))
            print('Received:',repr(pickle.loads(client.recv(1024))))

        client.close()

for x in range(5):
    ConnectionThread().start()

Сервер работает нормально, и когда я запускаю клиент, он успешно соединяется и начинает отправлять целые числа и получать их обратно в два раза, как ожидалось. Однако очень быстро это исключение:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\Python30\lib\threading.py", line 507, in _bootstrap_inner
    self.run()
  File "C:\Users\Imagist\Desktop\server\client.py", line 13, in run
    print('Received:',repr(pickle.loads(client.recv(1024))))
socket.error: [Errno 10053] An established connection was aborted by the softwar
e in your host machine

Сервер продолжает работать и получает соединения просто отлично; только сбой клиента. Что вызывает это?

EDIT: я получил клиент, работающий со следующим кодом:

import pickle
import socket
import threading

class ConnectionThread(threading.Thread):
    def run(self):
        for x in range(10):
            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            client.connect(('localhost', 2727))
            client.send(pickle.dumps(x))
            print('Sent:',str(x))
            print('Received:',repr(pickle.loads(client.recv(1024))))
            client.close()

for x in range(5):
    ConnectionThread().start()

Однако я все еще не понимаю, что происходит. Разве это не просто открытие и закрытие сокета кучу раз? Не должно быть ограничений по времени для этого (вы не сможете открыть сокет так вскоре после его закрытия)?

4b9b3361

Ответ 1

Теперь ваш клиент прав - вы хотите открыть сокет, отправить данные, получить ответ, а затем закрыть сокет.

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

Однако я все еще не понимаю что происходит. Разве это не просто открытие и закрытие гнезда куча раз?

Да. Это приемлемо, если не самый высокий способ выполнения действий.

Не должно быть времени ограничений на это (вы не должны быть возможность открыть сокет так скоро после закрытие)?

Вы можете открыть клиентский сокет так быстро, как вам нравится, так как каждый раз, когда вы открываете сокет, вы получаете новый номер локального порта, а это означает, что соединения не будут мешать. В приведенном выше коде сервера он начнет новый поток для каждого входящего соединения.

Для каждого IP-соединения есть 4 части (source_address, source_port, destination_address, destination_port), и этот квад (как известно) должен меняться навсегда. Все, кроме source_port, исправлено для клиентского сокета, так что OS меняется для вас.

Открытие сокетов для серверов более проблематично - если вы хотите быстро открыть новый серверный сокет,

server.bind(('', 2727))

Выше вы должны прочитать SO_REUSEADDR.

Ответ 2

Это не то, как вы изучаете сетевое программирование на питоне. Никто не делает ничего серьезного, никогда не будет так программироваться, поэтому вы учитесь, как НЕ выполнять сетевое программирование на основе python.

  • Сокеты слишком низкоуровневые, а python - это язык высокого уровня. Затем, чтобы выполнить сетевое программирование на питоне, питонным способом, вы хотите полностью отказаться от сокетов и оставить это для некоторого модуля или пакета. Если вы хотите узнать, как работает низкоуровневый материал, изучение существующих реализаций очень важно, так что изучение создает проблемы вместо, просто попробуйте избегайте их полностью. Сокеты (и, следовательно, библиотеки более высокого уровня, как обсуждалось в пункте 1), могут работать в неблокирующем режиме, где вы можете работать, пока другой код и это можно сделать без использования потоков.

Я только что видел ваш комментарий к вопросу:

@leeroy (продолжение) Моя цель состоит в том, чтобы приступить к реализации чего-то вроде этого: http://www.mcwalter.org/technology/java/httpd/tiny/index.html только в Python

Ну, вот рабочая реализация:

from SimpleHTTPServer import SimpleHTTPRequestHandler as RH
from SocketServer import TCPServer

print "serving current directory at port 8000"
TCPServer(("", 8000), RH).serve_forever()