GCDAsyncSocket: [socket acceptOnPort: error:] not accepting

GCDAsyncSocket: [socket acceptOnPort: error:] not accepting

所以我一直在尝试在我的项目中创建两个 GCDAsyncSocket,一个 (socket) 将文件上传到我的服务器,另一个 (listenSocket) 等待供服务器中的另一个进程与之通信。在我的 ViewController 中,我在 viewDidLoad 方法中初始化了它们,并为两个套接字设置了 delegateself

socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

然后我让 listenSocket 开始收听

NSError *err = nil;
if (![listenSocket acceptOnPort:19920 error:&err]) {
    NSLog(@"listenSocket failed to accept: %@", err);
}

然后我 socket 连接到远程服务器并开始上传文件。

问题是 socket 工作正常,可以上传并从我的服务器读取响应,但似乎我无法以任何方式访问接受 listenSocket。不是通过服务器上的其他进程,也不是通过使用 telnet 或通过在浏览器中输入 ip 地址和端口号。为什么会这样,我该如何解决?


编辑:

这是我使用我的应用程序所做的事情:

我正在开发一个在 iPhone 上为 Arduino 编程的应用程序。由于 App Store 政策,编译和上传过程必须在服务器上进行,所以我使用 socket 将代码上传到服务器以进行编译。为了将编译后的二进制文件上传到 Arduino,我必须 运行 avrdude 幸运的是它会接受 ip + 端口地址而不是 usb 连接作为目标。 avrdude 已实现,以便它作为客户端连接到该地址,因此我必须在我的应用程序上打开一个监听套接字。

我想您的问题与您的设备没有来自外界的可路由 IP 地址有关。我在这里假设您没有在本地网络上使用您的服务器进行测试,并且 phone 都通过 wifi/cable.

使用此网络

当您在设备上使用移动网络时,移动运营商会为其分配一个 IP 地址。该地址很可能是属于其内部移动网络一部分的地址。当您在移动网络外部连接到服务器时,服务器为您的设备看到的地址不是您在设备上看到的地址。当您的 IP 数据包在到达服务器的途中通过各种网关时,这些地址在传输过程中被映射。因此,当您的服务器看到在侦听套接字上请求的连接时,它有一个回复地址,使用该地址允许回复遍历回您的设备。

当您的设备在 NAT 路由器后面的 WiFi 上时,会出现类似的问题。路由器可以看到传出的连接,并将发件人 IP 地址更改为路由器的 IP 地址。因为它看到对话的开始,所以它知道应该将具有给定端口和顺序的 return 数据包路由到哪里。但是,如果有人想从外部连接到您的设备,您必须在路由器上为已知端口设置端口转发,告诉它向何处发送连接数据包。

因此将此应用于您的情况:

外传作品(为什么):

您的传出套接字有效,因为您正在连接到一个外部可见的 IP。当您连接时,网络确切地知道数据包必须去哪里,并且网络在数据包中提供回复地址。

传入不起作用(为什么):

您的侦听套接字将无法工作,因为您要发送到的地址在开放的互联网上不存在。要从服务器或其他任何地方连接到您的设备,您需要一个具有映射到您设备的路由的 IP。如果设备在移动网络上,您需要一个映射到您设备的移动网络的外部 IP。如果设备位于 NAT 路由器后面,则需要设置端口转发。

解法:

不幸的是,没有简单的解决方案,因为您需要一个外部世界设备的 IP 地址。很大程度上取决于您没有提到的用例。您要么需要一个可靠的外部 IP,要么需要使用中间服务器来处理消息传递,或者您需要改变方法并让设备不时轮询以获取信息。

这是一个长期存在的问题,也是为什么点对点公司拥有连接点对点服务的智能算法,这些服务使用打孔等智能技术连接设备。

恕我直言,如果可以的话,我会转向您的设备始终启动连接的模型。