![Как мне получить доступ к открытому и прослушиваемому порту в Linux?](https://rvso.com/image/76414/%D0%9A%D0%B0%D0%BA%20%D0%BC%D0%BD%D0%B5%20%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C%20%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%20%D0%BA%20%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D0%BC%D1%83%20%D0%B8%20%D0%BF%D1%80%D0%BE%D1%81%D0%BB%D1%83%D1%88%D0%B8%D0%B2%D0%B0%D0%B5%D0%BC%D0%BE%D0%BC%D1%83%20%D0%BF%D0%BE%D1%80%D1%82%D1%83%20%D0%B2%20Linux%3F.png)
После переадресации порта, который я хочу открыть, я не могу подключиться или получить какие-либо данные на этот порт. Программное обеспечение PHP CLI, которое я написал, активно прослушивает порт наУбунту 14.04. Часть кода показана ниже. Порт открыт как AF_INET, скрипт не выдает ошибок для каждой строки, а в /etc/protocols tcp определен как 'tcp 6 TCP'.
// I have tried $host=gethostbyname(gethostname());$port=8399 (host is 127.0.1.1)
// as well as $host = '0.0.0.0'; $port = 8399; and other addresses
$this->wsRead[0] = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
socket_set_option($this->wsRead[0], SOL_SOCKET, SO_REUSEADDR, 1)
socket_bind($this->wsRead[0], $host, $port)
socket_listen($this->wsRead[0], 10)
while (isset($this->wsRead[0])) { /* Handshake/Process data, etc. */ }
Порты переадресованы и мойiptables пусты, хотя я пробовал специально добавлять разрешающее правило для порта. Я пробовал запускать скрипт как суперпользователь. Когда сервер слушает, netstat -tuln выводит эту строку (с моим портом 8399), и я замечаю, что apache также выводится, что работает нормально и отображается как открытый порт на внешних сайтах проверки портов (на порту 8301):
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:8399 0.0.0.0:* LISTEN
tcp6 0 0 :::8301 :::* LISTEN
tcp6 0 0 :::80 :::* LISTEN
Используя nmap, порт также показывает, что он открыт. Я также пробовал разные порты. Мой клиентский скрипт подключения — это скрипт JavaScript websocket, который работает для подключения при запуске PHP CLI в Windows. Скрипт слишком длинный, чтобы включать его здесь, и он не подключается из внешней сети. Если я устанавливаю оба скрипта JS и PHP на локальные адреса 127.0.0.1 или 192.168.0.###, то он работает, но не с устройства за пределами моей локальной сети.
// The JS is basically this, plus some connection events to alert success/fail.
// This external connection request will always time out
Server = new WebSocket('ws://68.215.154.129:8399');
Может, мне не хватает какого-то брандмауэра в Linux, кроме iptables, который я не обхожу? Apache правильно открывает порты и другое ПО на ПК, но, похоже, в моем скрипте отсутствует необходимый шаг для полного открытия порта для внешнего использования.
tl,dr; Подключение с использованием внешнего IP-адреса с помощью JavaScript-клиента к PHP-серверу, работающему в Windows, но не в Ubuntu.Порт перенаправлен, прослушивается, не блокируется iptables, то, что осталось?
решение1
Вы что-то упускаете концептуально и в коде. У вас есть PHP-код, который прослушивает соединения, но вы должны принять соединение перед его использованием.
$ns = socket_accept($this->wsRead[0]);
$some_string = socket_read($ns, 128);
Вызов socket_accept()
блокирует. Он не вернется, пока какая-либо клиентская программа не подключится к программе, ожидающей соединения.
Вызов socket_accept()
возвращает фактический сокет, который вы используете для связи с удаленной программой. Я не думаю, isset()
что это действительно то, что вам нужно, вам следует изучить socket_select()
или что-то в этом роде. Когда вы закончите общаться с удаленным, вы вызываете socket_close($ns)
, а затем возвращаетесь к вызову, socket_accept($this->wsRead[0])
чтобы дождаться, пока другая удаленная программа подключится к вашей программе.
Когда ваша PHP-программа завершает обработку соединений, она должна вызвать socket_close($this->wsRead[0])
функцию закрытия сокета, что по сути означает, что ядру ОС следует прекратить прослушивание входящих TCP SYN-пакетов для указанного вами порта.
решение2
Оказывается, проблема была в нескольких вещах, в основном из-за моего модема/маршрутизатора. Я используюМоторола SB6580, который недавно обновил прошивку и не перезагружался в течение 10 дней, из-за чего он стал работать довольно медленно и мне не хотелось вносить в него слишком много изменений.
Theобновление прошивки изменило страницу переадресации портоввключить раздел адреса внешнего удаленного хоста (по умолчанию 0.0.0.0) — тут проблем нет, но что-то еще, что они сделали, нарушило существующие правила переадресации портов, которые я установил.
Я использовал диапазон портов для переадресации, который не работал, и, изменив этот диапазон на 8399 - 8399, он снова заработал. Перезапуск не повлиял на него, кроме увеличения скорости модема, как и изменение протокола с Both на TCP.
IP Addr|Start Port|End Port|Remote Host Addr|Start Port|End Port|Protocol|Enabled
192.168.0.101|8340| 8399| 0.0.0.0| 8340| 8399| Both|Checked
192.168.0.101|8399| 8399| 0.0.0.0| 8399| 8399| TCP|Checked
Кроме того, при использовании команды PHP gethostbyname(gethostname()) в Linux возвращаемый адрес является локальным адресом 127.0.1.1, второй записью в файле /etc/hosts, которая не будет работать для привязки сокета. $_SERVER['REMOTE_ADDR'] также возвращает предупреждение: невозможно найти хост. Повручную изменить его на домашний адрес (подсети?) (мой 192.168.0.101) или подстановочный знак IPv4 0.0.0.0, прослушиватель сокетов привязан правильно и принимает внешние соединения.
Мой опыт работы с маршрутизатором и неопытность в Linux заставили меня склониться к неправильному пути устранения неполадок Linux. Заметив, что и в Windows 7 все не работает, я внес 2 изменения выше, и теперь все работает как надо.