Словарь сокетов Python с select

#python #sockets #dictionary

#python #сокеты #словарь

Вопрос:

По какой-то причине я не могу сопоставить выбранные сокеты с моим словарем сокетов. Приведенный ниже код создает словарь сокетов (который есть), а затем, когда кто-то подключается, принимает (чего он не делает). Он находит ‘s’ в ‘L’, но затем не может socket.error: [Errno 22] Invalid argument

 listening = {}
L = []
for link in links:
    try:
        # listening
        listening[link] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        listening[link].bind((host, routers[routername].baseport links[link].locallink))
        listening[link].listen(backlog)
        # append routes and listen-list
        L.append(listening[link])
    except socket.error, (value,message):
        print "Could not open socket: "   message
        sys.exit(1)

# run loop
input = L
running = 1
while running:
    inputready,outputready,exceptready = select.select(input,[],[], 0)

    # Sockets loop
    for s in inputready:
        if s in L:
            # handle the server socket
            client, address = s.accept()
            input.append(client)
  

Комментарии:

1. Ваш вводный абзац меня смущает… не могли бы вы немного пояснить?

2. Я бы с удовольствием, какую конкретно часть или вы имеете в виду все целиком?

3. У меня возникли проблемы с разбором второго и третьего предложений.

4. s это итератор в цикле for, который обрабатывает все готовые сокеты из инструкции select, и я теряюсь, пытаясь описать ошибку. Что касается предыдущего утверждения, я просто пытался описать свое затруднительное положение. С тех пор я решил свою дилемму и опубликую упрощенное решение ниже.

Ответ №1:

Я думаю, проблема в том, что когда вы добавляете клиентский сокет append в (input), вы также добавляете его в (L). Это происходит потому, что input и L оба указывают на один и тот же объект list. Затем, когда недавно подключенный клиентский сокет отправляет вам некоторые данные, вы пытаетесь вызвать accept() в клиентском сокете, но, конечно, клиентский сокет не является прослушивающим сокетом, поэтому вы получаете ошибку, которую вы видели.

В качестве примера того, почему input.append(client) добавляет client в L, вот фрагмент из моего интерпретатора Python:

 Jeremys-Mac-mini:python lcsuser1$ python
Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> L = [1,2,3]
>>> print L
[1, 2, 3]
>>> input = L
>>> print input
[1, 2, 3]
>>> input.append(4)
>>> print input
[1, 2, 3, 4]
>>> print L
[1, 2, 3, 4]  <-- d'oh!
  

Для исправления замените строку

 input = L
  

с

 input = list(L)
  

Таким образом, входные данные указывают на копию L, а не на сам L.

Ответ №2:

Хотя я не был уверен во всех своих ошибках с первой попытки, с тех пор я решил свою собственную дилемму. @Jeremy был на правильном пути, но немного сбился (вероятно, из-за моего описания). Ссылки на сокеты не отображаются за пределами s и, следовательно, не обязательно должны быть словарем. Однако select принимает только список, поэтому вместо того, чтобы усложнять работу с другими типами данных, используйте список и ссылку s вместо L ( s это то, что вы хотите в любом случае)

 L = []
input = [sys.stdin]

for i in range(4):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    server.bind((host,port i)) 
    server.listen(backlog)
    L.append(server)
    input.append(server)

running = 1
print len(L)
while running: 
    inputready,outputready,exceptready = select.select(input,[],[]) 

    for s in inputready: 
        if s in L: 
            # handle the server socket
            print "opened"
            client, address = s.accept() 
            input.append(client)
        elif s == sys.stdin: 
            # handle standard input 
            junk = sys.stdin.readline() 
            running = 0 
        else: 
            # handle all other sockets 
            data = s.recv(size)