【发布时间】:2019-03-29 12:25:31
【问题描述】:
我正在尝试将数据从一台远程计算机 (Ubuntu) 发送到我的家用计算机 (High Sierra)。我已经在 SO 阅读了a couple of questions ,但他们似乎没有解决我的问题。我通过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 地址。这个端口是随机选择的,因为iana 已将其标记为未分配,而且它相当大。由于我可以在一台机器上运行这两个程序时发送数据,我认为端口不是问题。
防火墙阻止了连接。
我已确保禁用本地计算机的防火墙(在系统偏好设置 -> 安全和隐私 -> 防火墙中),并在我的路由器中创建一个条目,允许来自远程计算机的消息(使用其公共 IP 地址)通过端口 38473。
我似乎仍然无法连接。我跑了Wireshark,可以看到遥控器确实发送了一个SYN请求,但得到了一个[RST,ACK]作为回报。 RST flag 似乎是防火墙终止连接的一种方式,但考虑到我之前的配置,我不明白为什么它会这样做。
我做错了什么?
【问题讨论】:
-
你的服务器只监听 localhost (127.0.0.1)。它需要监听所有 IP 或流量将进入的 IP(本地 IP),例如 192.168.1.2(或其他)。
-
PS--通常“连接被拒绝”表示未侦听与超时,这通常表示防火墙或路由器刚刚丢弃了流量(这是它们通常的行为方式)
-
@zzxyz 哦,好吧,正如许多人写的那样“连接被拒绝”意味着端口没有监听,我认为地址无关紧要,它总是监听所有传入地址。但是不这样做是有道理的:P 我现在尝试将 IP 地址更改为 0.0.0.0 并且它起作用了!谢谢! ^^
-
鉴于大多数示例代码很容易犯错误......对不起你的痛苦:)
标签: c++ sockets tcp port firewall