重用套接字时出现套接字使用错误

2024-03-29 06:53:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用c++编写一个XMLRPC客户机,它旨在与python XMLRPC服务器通信。

不幸的是,此时python XMLRPC服务器只能在一个连接上部署一个请求,然后它会关闭,我发现这要感谢mhawke对我之前关于related subject的查询的响应

因此,每次我想发出XMLRPC请求时,都必须创建到python服务器的新套接字连接。这意味着创建和删除许多套接字。一切正常,直到我接近4000个请求。此时,我得到套接字错误10048, Socket in use

我试着让线程休眠,让winsock修复它的文件描述符,当我的一个python客户机遇到相同的问题时,这个技巧奏效了,但没有用。 我已经试过了

int err = setsockopt(s_,SOL_SOCKET,SO_REUSEADDR,(char*)TRUE,sizeof(BOOL));

没有成功。

我使用的是Winsock2.0,因此WSADATA::iMaxSockets不应该起作用,不管怎样,我检查了它并将其设置为0(我认为这意味着无穷大)

4000个请求看起来不像是在应用程序运行期间发出的奇怪请求数。当服务器持续关闭并重新打开时,是否有办法在客户端使用“保持”命令?

我完全错过什么了吗?


Tags: 文件in服务器客户机use部署错误socket
3条回答

更新:

我把它扔进代码里,现在它好像在工作。

if(::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) 
  {
    int err = WSAGetLastError();
    if(err == 10048)   //if socket in user error,   force kill and reopen socket
    {
        closesocket(s_);
        WSACleanup();
        WSADATA info;
        WSAStartup(MAKEWORD(2,0), &info);
        s_ = socket(AF_INET,SOCK_STREAM,0);
        setsockopt(s_,SOL_SOCKET,SO_REUSEADDR,(char*)&x,sizeof(BOOL));
    }
  }

基本上,如果遇到10048错误(socket正在使用),只需关闭socket,调用cleanup,然后重新启动WSA,重置socket及其sockopt

(可能不需要最后一个sockopt)

我以前一定错过了WSACleanup/WSAStartup调用,因为closesocket()和socket()确实被调用了

这个错误每4000ish个调用只发生一次。

我很好奇这是为什么,尽管这似乎解决了它。 如果有人对这个问题有什么意见,我很想听听

该问题是由于在关闭客户机的套接字后进入的时间等待状态中挂起的套接字引起的。默认情况下,套接字在可重用之前将保持此状态4分钟。您的客户(可能有其他流程的帮助)在4分钟内将它们全部消耗掉。请参阅this answer以获得良好的解释和可能的非代码解决方案。

如果不显式绑定套接字地址,Windows将动态分配1024-5000(3977个端口)范围内的端口号。此Python代码演示了问题:

import socket
sockets = []
while True:
    s = socket.socket()
    s.connect(('some_host', 80))
    sockets.append(s.getsockname())
    s.close()

print len(sockets)    
sockets.sort()
print "Lowest port: ", sockets[0][1], " Highest port: ", sockets[-1][1]
# on Windows you should see something like this...
3960
Lowest port: 1025  Highest port: 5000

如果您尝试立即再次运行此命令,它将很快失败,因为所有动态端口都处于时间等待状态。

有几种方法可以解决这个问题:

  1. 管理自己的端口分配和 使用bind()显式绑定 到特定端口的客户端套接字 你每增加一次 创建套接字。你还是会有 处理端口所在的情况 已经在使用,但你不会 仅限于动态端口。e、 g

    port = 5000
    while True:
        s = socket.socket()
        s.bind(('your_host', port))
        s.connect(('some_host', 80))
        s.close()
        port += 1
    
  2. 摆弄SOúLINGER插座 选择。我发现这个 有时在Windows中工作(尽管 不确定原因): s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 1)

  3. 我不知道这是否有帮助 你的特殊申请, 但是,可以发送 通过 使用 multicall方法。基本上 这让你可以积累 几个请求然后发送 一下子。你不会得到任何 回复直到你真正发送 累积的请求,因此您可以 基本上可以把它看作批处理 处理-这是否符合 你的应用程序设计?

使用后是否关闭插座?

相关问题 更多 >