将现有套接字重新连接到新服务器所需的最小工作量是多少?

时间:2017-10-17 22:48:57

标签: c++ linux sockets

鉴于以下伪代码...... int sock = socket(AF_INET,SOCK_STREAM,0); sockaddr_in si; si.sin_family = AF_INET; si.sin_port = 0; si.sin_addr.s_addr = htonl(inet_network(" 127.0.0.100")); bind(sock,(sockaddr *)& si,sizeof si); ... struct sockaddr_in peer_addr; inet_pton(AF_INET," 127.0.0.200",& peer_addr.sin_addr); peer_addr.sin_family = AF_INET; peer_addr.sin_port = htons(9000); connect(sock,(sockaddr *)& peer_addr,sizeof peer_addr)); ...假设connect()成功,然后对等体关闭与listen()一起使用并由accept()返回的各自套接字,是否可以将sock作为subsequenet connect()的参数重用不同的同行地址? 实验上,答案似乎是" no":虽然第二个connect()返回0,但我尝试连接的第二个对等体永远不会从accept()返回。知识渊博的回答者可以解释这里出了什么问题的本质吗? 0返回值应该表示成功,那么为什么对等的accept()永远不会解除阻塞? 我可以做些什么来重用袜子连接到第二个同伴?或者第二次connect()是否必须使用socket()新创建的套接字完成? (我已经证实这样做有效)

2 个答案:

答案 0 :(得分:2)

  

将现有套接字重新连接到新服务器所需的最小工作是什么?

无限。这是不可能的。

  

是否可以将sock作为具有不同对等地址的subsequenet connect()的参数重用?

没有。调用connect()后,即使失败,也无法重新连接TCP套接字。您必须关闭它并创建一个新的套接字。一个原因是如果套接字没有绑定,connect()绑定它,并且根据到目的地的IP路由选择绑定,这对于第二个目的地可能不相同。

  

虽然第二个connect()返回0

难以置信。你确定吗?

  

我尝试连接的第二个对等体永远不会从listen()返回。

listen()没有阻止。你的意思是accept()

  

知识渊博的回答者可以解释这里出现问题的本质吗?

再次,你必须指accept(),而且很难相信第二个connect()返回零。 connect()应该在errno == EISCONN(或Windows上为WSAGetLastError() == WSAEISCONN)时返回-1。

编辑但是,在非阻塞套接字上第二次调用connect()用于检测第一个connect()是否已完成。这项技术在所有旧书中都有,但现在我们SO_ERROR正确的方法是检查getsockopt(SO_ERROR)是否有EAGAIN / EWOULBLOCK来自第一个connect() }}。当您收到来自select()的写入通知或来自(e)poll()的写入或错误通知时,您会执行这些检查。所以在你的情况下发生的一切是第二个connect()确认了第一个connect()的成功,并忽略了不同的目标地址/端口。

  

0返回值应该表示成功,那么为什么对等体listen()永远不会解除阻塞?

无论外观如何,第二个connect()都失败了,所以服务器没有理由做任何事情,更不用说从accept()返回了。

  

我可以做些什么来重用sock来连接第二个对等体?

没有

  

或者第二次connect()是否必须使用socket()新创建的套接字完成?

答案 1 :(得分:2)

  

是否可以将sock作为参数重新使用具有不同对等地址的子结构connect()

对于TCP套接字,不可能(对于UDP套接字,它是允许的)。 TCP套接字关闭后,无法重用。每次socket()来电时,您需要另外connect()来电。

然而,仅在Windows上,SOCKET(来自socket()WSASocket()可以重复使用,但它使用DisconnectEx()关闭,dwFlags参数设置为TF_REUSE_SOCKET。然后,SOCKET可以传递给ConnectEx()(或AcceptEx())。