Я пытаюсь отправить данные с одного удаленного компьютера (Ubuntu) на свой домашний компьютер (High Sierra). Я прочитал аа> параизвопросов здесь, в SO, но они, похоже, не дают решения моей проблемы. Я подключился к удаленному компьютеру с помощью ssh и создал и успешно скомпилировал следующие программы на обоих компьютерах.
client.cpp
#include <iostream>
#include <string>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char* argv[])
{
std::string address = argv[1];
int port = 38473;
int success;
// http://man7.org/linux/man-pages/man2/socket.2.html
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1)
return errno;
sockaddr_in socket_address{};
socket_address.sin_family = AF_INET;
socket_address.sin_port = htons(port); // htons - Host to Network Short. Flip endianness to match machine.
success = inet_pton(AF_INET, address.c_str(), &socket_address.sin_addr); // Pointer (to String) to Number.
if (success <= 0)
return errno;
success = connect(server_socket, (sockaddr*)&socket_address, sizeof(socket_address));
if (success == -1)
return errno;
std::cout << "Connected" << std::endl;
for (int i = 0; i < 10; ++i)
write(server_socket, "Hello!\n", 7);
}
server.cpp
#include <iostream>
#include <string>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char* argv[])
{
std::string address = "127.0.0.1";
int port = 38473;
int success;
// http://man7.org/linux/man-pages/man2/socket.2.html
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket == -1)
return errno;
sockaddr_in socket_address{};
socket_address.sin_family = AF_INET;
socket_address.sin_port = htons(port); // htons - Host to Network Short. Flip endianness to match machine.
success = inet_pton(AF_INET, address.c_str(), &socket_address.sin_addr); // Pointer (to String) to Number.
if (success <= 0)
return errno;
// http://man7.org/linux/man-pages/man2/bind.2.html
success = bind(listen_socket, (sockaddr*)&socket_address, sizeof(socket_address));
if (success == -1)
return errno;
// http://man7.org/linux/man-pages/man2/listen.2.html
success = listen(listen_socket, 10);
if (success == -1)
return errno;
sockaddr_in client_address;
socklen_t client_address_size = sizeof(client_address);
int client_socket = accept(listen_socket, (sockaddr*)&client_address, &client_address_size);
if (client_socket == -1)
return errno;
close(listen_socket);
size_t buffer_size = 4096;
char buffer[buffer_size];
ssize_t bytes_received;
std::cout << "Connected" << std::endl;
while (true)
{
memset(buffer, 0, buffer_size);
// http://man7.org/linux/man-pages/man2/recvmsg.2.html
if ((bytes_received = read(client_socket, buffer, buffer_size)) <= 0)
return 0;
std::cout << "Message: " << buffer << std::endl;
}
}
При запуске обеих программ на одном компьютере (где исполняемый файл клиента принимает 127.0.0.1 в качестве аргумента в командной строке), он работает отлично, и данные отправляются. При попытке запустить локальный компьютер в качестве сервера и запустить client.cpp с удаленного компьютера, я получаю код ошибки 111 (соединение отклонено).
После прочтения различных руководств / блогов / сообщений, похоже, что это:
Я попытался решить эту проблему, выполнив следующие действия.
Поскольку удаленная машина пытается подключиться к моему общедоступному IP-адресу, я должен перенаправить порт на мою локальную машину. Я вошел в свой маршрутизатор и добавил запись для перенаправления порта 38473 на мой частный IP-адрес. Этот порт был выбран случайным образом, поскольку Иана пометил его как неназначенный, и он был довольно большим. Поскольку я могу отправлять данные при запуске обеих программ на одном компьютере, я предполагаю, что проблема не в порту.
Я обязательно отключил свой брандмауэр на локальном компьютере (в Системных настройках -> Безопасность и конфиденциальность -> Брандмауэр) и сделал запись в моем маршрутизаторе, разрешающую сообщения с удаленного компьютера (используя его общедоступный IP-адрес) через порт 38473.
Кажется, я все еще не могу подключиться. Я запустил Wireshark и увидел, что удаленный компьютер действительно отправил SYN-запрос, но получил взамен [RST, ACK]. Флаг RST кажется способом для брандмауэра прервать соединение, но я не понимаю, зачем он это делал, учитывая мои предыдущие конфигурации выше.
Что я делаю неправильно?
PS - Обычно «соединение отклонено» указывает на то, что не слушает, а таймаут обычно указывает на то, что брандмауэр или маршрутизатор только что сбросили трафик (как они обычно себя ведут)
@zzxyz О, хорошо, поскольку многие писали, что «Соединение отклонено» означает, что порт не прослушивает, я предположил, что адрес не имеет значения, и он всегда прослушивал все входящие адреса. Но есть смысл этого не делать: P Я попробовал изменить IP-адрес на 0.0.0.0, и это сработало! Спасибо! ^^
Легко сделать ошибку, учитывая большую часть примера кода .... Извините за ваши страдания :)
Настройте код вашего сервера так, чтобы он прослушивал IP-адрес интересующей вас сетевой карты на компьютере, ИЛИ:
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
Ваш сервер слушает только localhost (127.0.0.1). Ему необходимо прослушивать все IP-адреса или IP-адреса (местный IP), по которым будет поступать трафик, например 192.168.1.2 (или что-то еще).