Python 2.7 Порты для сокет программирования

1

У меня было упражнение портальной карусели, что означает, что мне нужно создать сервер-клиент, который сервер запрашивает у клиента для порта, а затем они начинают прослушивать порт, который был указан, и это цикл, в котором я получил ошибку, и я не знаю, как это исправить.

сервер:

import socket
import random

def main():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind(('0.0.0.0', 1729))
    server_socket.listen(1)
    (client_socket, server_socket) = server_socket.accept()

    done = False
    while not done:
        port = client_socket.recv(4096)
        client_socket.send('i got the port' + port)
        port = int(port)

        if port != 1:
            server_socket.bind(('0.0.0.0', port))
            continue
        else:
            done = True


if __name__ == '__main__':
    main()

клиент:

import socket
import random


def main():
    print 'hi at anytime enter 1 to break the loop'
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(('127.0.0.1', 1729))
    done = False

    while not done:
        port = client_socket.send(raw_input("enter port:"))
        data = client_socket.recv(4096)
        print data
        port = int(port)
        if port != 1:
            client_socket.connect(('127.0.0.1', port))
            continue
        else:
            done = True
    client_socket.close()


if __name__ == '__main__':
    main()

вывод ошибки для сервера:

Файл "C: /Cyber/ServerFolder/ports_carrousel.py", строка 18, в основном
server_socket.bind(('0.0.0.0', порт))
AttributeError: объект 'tuple' не имеет атрибута 'bind'

Теги:
python-2.7

2 ответа

2
Лучший ответ

В своей основной функции вы выполняете следующие действия:

(client_socket, server_socket) = server_socket.accept()

но server_socket.accept() фактически возвращает два объекта. Первый - это объект сокета, а второй - кортеж, который содержит (sourceIPString, sourcePort).

Таким образом, используя эту строку кода, описанную выше, вы по существу переопределяете server_socket объектом кортежа. Обратите внимание, что позже, в строке 18, вы пытаетесь получить доступ к функции "привязки" сокета, но, используя ссылку на объект кортежа, который не реализует такую функцию.

То, что вы должны делать, - это нечто вроде

(client_socket, client_connection_info) = server_socket.accept()

и соответствующим образом скорректируйте свой код.

1

Здесь всего пара ошибок. Во-первых, accept возвращает 2-кортеж, содержащий вновь подключенный сокет, и адрес клиента (который сам по себе является 2-кортежем IP-адреса и номера порта). Он не возвращает два сокета. Но вы переписываете переменную server_socket со вторым возвращаемым значением. Это не имеет смысла, и почему интерпретатор говорит вам, что 2-кортеж не имеет атрибута bind: он не является объектом сокета. accept вызова должен выглядеть примерно так:

client_socket, client_addr = server_socket.accept()

Затем, после получения нового номера порта от клиента, вы должны создать новый сокет (вы не можете повторно использовать один и тот же прослушивающий сокет), а затем bind этот новый сокет к новому порту, а затем listen; наконец, вы можете accept новое клиентское соединение из нового прослушивающего сокета.

Вы также должны close сокеты, которые вы закончили, чтобы вы не просачивали файловые дескрипторы. Это означает, что каждый раз, когда вы получаете новый номер порта от клиента, вы должны закрыть клиентский сокет и прослушивающий сокет, затем создать новый прослушивающий сокет (и bind и listen), а затем принять новый клиентский сокет.

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

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

РЕДАКТИРОВАТЬ:
Кроме того, при повторном подключении вы должны создать новый сокет на стороне клиента. Как только сокет потока связан с портом (что также происходит автоматически при connect), вы никогда не сможете использовать его для bind или connect к другому адресу/порту.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню