Как использовать установку клиент / сервер с сокетом Python 3 через Интернет (не локально)? - PullRequest
0 голосов
/ 06 июня 2018

Я пытаюсь реализовать простую программу чата, которая использует сокеты для передачи данных через соединение UDP.Однако я не могу понять, как правильно настроить его так, чтобы люди из-за пределов моей локальной сети могли получить к нему доступ, если я размещаю его на своем ноутбуке.Я использую порт 5000 и перенес этот порт на моем маршрутизаторе для моего ноутбука.Переадресация портов, похоже, не является проблемой;По крайней мере, «Утилиты сетевой переадресации портов» от portforward.com, похоже, обнаруживают, что они правильно перенаправлены.Может быть, я смешиваю IP-адреса, с которых мне нужно хоститься и с которыми соединяться?Ниже приведен код:

import socket
import threading
import sys


class Server:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connections = []

    def __init__(self):
        self.sock.bind(('192.168.1.5', 5000))
        self.sock.listen(1)

    def handler(self, c, a):
        while True:
            data = c.recv(1024)
            for connection in self.connections:
                print(data.decode())
                connection.send(data)
            if not data:
                break

    def run(self):
        while True:
            c, a = self.sock.accept()
            cThread = threading.Thread(target=self.handler, args=(c, a))
            cThread.daemon = True
            cThread.start()
            self.connections.append(c)
            print(self.connections)


class Client:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    usr_name = ""

    def sendMsg(self):
        while True:
            self.sock.send(bytes(self.usr_name + ": " + input("-> "), 'utf-8'))

    def __init__(self, address):
        self.sock.connect((address, 5000))
        self.usr_name = input("Enter a username: ")
        iThread = threading.Thread(target=self.sendMsg)
        iThread.daemon = True
        iThread.start()

        while True:
            data = self.sock.recv(1024)
            if not data:
                break
            print(data.decode())


if len(sys.argv) > 1:
    client = Client(sys.argv[1])
else:
    server = Server()
    server.run()

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

Заранее спасибо.

Редактировать: две основные ошибки, которые я получаю:

  • Ошибка тайм-аута [WinError 10060]
    • Мой другполучил это при попытке подключения из другой сети
  • [WinError 10061]
    • Я получил бы это при попытке подключения с использованием моего публичного IP с того же компьютера

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

Редактировать: Я смог переписать его и заставить его работать, мне больше не нужна помощь с этим.Спасибо.

1 Ответ

0 голосов
/ 06 июня 2018

Вы переадресовываете порт UDP с 5000 на 5000.

Но вы открываете потоки TCP, а не UDP.Вот что означает SOCK_STREAM.Если вы хотите UDP, вам нужно использовать SOCK_DGRAM.

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

С одной стороны, ваш код ориентирован на соединение recv и, похоже, предполагает надежную передачу, а это значит, что вывозможно, вам нужен TCP.

С другой стороны, ваш код, похоже, предполагает, что каждый recv(1024) собирается получить ровно один send с другой стороны, что верно только для UDP; TCP-сокеты - это байтовые потоки, а не потоки сообщений .Когда вы делаете recv(1024), вы можете легко получить только первые 12 байтов 80-байтовой строки, что означает, что оно может заканчиваться в середине символа UTF-8, что означает, что decode сгенерирует исключение.

Я думаю, что вы хотите TCP, но с протоколом кадрирования поверх него.Простейший протокол, который, вероятно, имеет здесь смысл, - это строки текста.Это довольно легко сделать самостоятельно, но еще проще с socket.makefile, учитывая, что вы выделяете поток для каждого соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...