TCP连接太多时,bind返回 10055 错误?

时间:2021-05-05 20:21:55
写这样一个程序,检测 某机子的某端口TCP 是否存活,我采用如下过程进行检测:
1、closesocket 
2、socket(获取socket)
3、bind 自己机子0端口(就是 让系统自己从动态端口范围中去取)
4、connect (连接目标机)
然后半分钟循环一次(即每次都先 关闭socket、打开socket、bind、连接X机子的Y端口),用了WSAEventSelect异步的方式来做。

这样做,目标机子数目比较少时间较短时,没发现数目问题。
但是我将目标机的数量变成100个(其中大概有80个左右TCP是能连上的),然后循环检测这100个机子,在跑了 3个小时左右,bind开始出现 10055 错误(WSAENOBUFS),意思是 “缓冲区空间不足或列队已满 ,或者是 连接太多了”。

我没发送数据也没接数据,和缓冲区有关?
我每次的操作第一步就是关闭上次的 socket,然后再申请新的socket进行操作,这样也会 “连接太多”?

请问这是啥原因?如何解决?急啊,求解~~

55 个解决方案

#1


怀疑是你关闭socket问题,看看这个行不行。

void __fastcall ForceCloseSocket(SOCKET &s,bool bClose)
{
  bool bDontLinger = false;
  setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(char *)&bDontLinger,sizeof(bool));

  linger InternalLinger;
  InternalLinger.l_onoff = 1;
  InternalLinger.l_linger = 0;

  setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&InternalLinger,sizeof(linger));

  if(bClose)
  {
    closesocket(s);
    s = INVALID_SOCKET;
  }
}

#2


或者你可以DisconnectEx然后重用socket句柄
http://kasicass.blog.163.com/blog/static/39561920084884555205/

#3


setsockopt(SOCKET, SOL_SOCKET, SO_REUSERADDR, ...);
试试

#4


to 3楼 VisualEleven
  经测试,一样

to 1楼 gibsonboy
  这个不就是设置 TIME_Wait 会有用么?试试去~

#5


引用 1 楼  的回复:
怀疑是你关闭socket问题,看看这个行不行。

刚完成的测试结果,还是一样啊~

#6


外行说两句:
1、从叙述看运行开始是没问题的,3小时候出现,那么就是累积的,缓冲区是否是已经累计了一些错误信息。或某一刻,链接过多给出信息故,累积出来的。
2、程序中一些功能函数添加判断,比如是否关闭成功了等等。

#7


引用 6 楼  的回复:
外行说两句:
1、从叙述看运行开始是没问题的,3小时候出现,那么就是累积的,缓冲区是否是已经累计了一些错误信息。或某一刻,链接过多给出信息故,累积出来的。
2、程序中一些功能函数添加判断,比如是否关闭成功了等等。

WsaSocket setsockopt bind WsaEventSelect connect
都加了 显示错误信息 ,直到 10055之前都么有错误信息显示出来

#8


你确定你安全释放socket吗?任务管理器的句柄数如何?

没问题的话看看这个  http://worldoffang.ycool.com/post.3676750.html

#9


引用 8 楼  的回复:
你确定你安全释放socket吗?任务管理器的句柄数如何?

没问题的话看看这个 http://worldoffang.ycool.com/post.3676750.html

何谓 “安全释放”? 
“句柄数” 倒是没注意,得看看

#10


觉得你的步骤怪怪的
应该是socket -> connect -> closesocket
bind是不必要的,bind端口0更是没必要
还有为什么closesocket放第一步?
猜是closesocket处理不好

另外在控制台输入命令netstat -an看一下

#11


本帖最后由 oyljerry 于 2012-06-08 09:35:08 编辑
引用 8 楼  的回复:
你确定你安全释放socket吗?任务管理器的句柄数如何?

没问题的话看看这个 http://worldoffang.ycool.com/post.3676750.html

貌似"句柄数"确实在增加,不见减少。怎么“安全释放”?  

#12


socket(),函数初始化一次,就有了一个句柄了,对应的,用closesocket关闭了,就没事了,需要注意的就是,匹配好初始化与关闭的代码

#13


引用 10 楼  的回复:
还有为什么closesocket放第一步?

因为我 第一步 关闭的 socket 是上次创建的socket ,
然后这次创建的 socket ,到下次第一步时关闭。

引用 10 楼  的回复:
觉得你的步骤怪怪的
应该是socket -> connect -> closesocket
bind是不必要的,bind端口0更是没必要

我现在吧 bind 去掉了,轮到 connect 返回10055了

#14


把出现10055时,netstat的结果贴出来。
最好把代码也贴上来。
现在的描述很难回答。

#15


http://msdn.microsoft.com/en-us/library/windows/desktop/ms737582(v=vs.85).aspx
看一下CloseSocket的官方文档,仔细看标记NOTE的文本,怎么释放socket。

另外也可以看这个 http://hi.baidu.com/info_sec/blog/item/61978eb7608a5af531add15b.html

#16


引用 14 楼  的回复:
把出现10055时,netstat的结果贴出来。
最好把代码也贴上来。
现在的描述很难回答。


Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    opos1:http             opos1:0                LISTENING
  TCP    opos1:epmap            opos1:0                LISTENING
  TCP    opos1:microsoft-ds     opos1:0                LISTENING
  TCP    opos1:1079             opos1:0                LISTENING
  TCP    opos1:2869             opos1:0                LISTENING
  TCP    opos1:3306             opos1:0                LISTENING
  TCP    opos1:4783             opos1:0                LISTENING
  TCP    opos1:18386            opos1:0                LISTENING
  TCP    opos1:33673            opos1:0                LISTENING
  TCP    opos1:1049             opos1:0                LISTENING
  TCP    opos1:netbios-ssn      opos1:0                LISTENING
  TCP    opos1:microsoft-ds     192.168.3.103:1034     ESTABLISHED
  TCP    opos1:1038             UNKNOWN-110-75-161-145.aliyun.com:16000  ESTABLI
SHED
  TCP    opos1:3077             78.129.163.10:http     SYN_SENT
  TCP    opos1:3111             hosted-by.leaseweb.com:http  SYN_SENT
  TCP    opos1:3113             hosted-by.leaseweb.com:http  SYN_SENT
  TCP    opos1:3114             87.117.203.6:http      SYN_SENT
  TCP    opos1:3172             180.189.157.90:http    SYN_SENT
  TCP    opos1:3173             180.189.157.92:http    SYN_SENT
  TCP    opos1:3185             hosted-by.leaseweb.com:http  SYN_SENT
  TCP    opos1:3195             host-219-235-2-79.iphost.gotonets.com:http  SYN_
SENT
  TCP    opos1:3201             50.22.192.196-static.reverse.softlayer.com:http
 SYN_SENT
  TCP    opos1:3203             50.22.74.3-static.reverse.softlayer.com:http  SY
N_SENT

#17


引用 14 楼  的回复:
最好把代码也贴上来。
现在的描述很难回答。

代码是 Delphi 的,能看的就帮看看吧

begin
// 取得 socket 地址
  pskt := @FzcSkts.Fskts[_iSktIdx];

// *** ***
// 关闭 socket  
  CloseSocket(pskt^); 
  pskt^ := INVALID_SOCKET;

// *** ***
// 重新获取 socket值
  pskt^ := WsaSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nil, 0, 0{WSA_FLAG_OVERLAPPED});
  if pskt^=INVALID_SOCKET then
  begin
    iErr := WsaGetLastError;
    Txt_AppendMsg(now, 'zc_'+datetostr(now)+'_TCP_err.txt',
      'WsaSocket INVALID_SOCKET : '+inttostr(iErr) );
    ShowMsg('WsaSocket INVALID_SOCKET : '+inttostr(iErr));
  end;

// *** ***
// socket 事件关联
  if 0<>WsaEventSelect(pskt^, FzcSkts.FhEvents[_iSktIdx], FD_CONNECT) then
  begin
    iErr := WsaGetLastError;
    Txt_AppendMsg(now, 'zc_'+datetostr(now)+'_TCP_err.txt',
      'WsaEventSelect err : '+inttostr(iErr) );
    ShowMsg('WsaEventSelect err : '+inttostr(iErr));
  end;

// *** ***
// connect
  ZeroMemory(@siTo, sizeof(TSOCKADDRIN));
  siTo.sin_family := AF_INET;
  siTo.sin_port := htons(_p.port_i);
  siTo.sin_addr.S_addr := _p.iDnsIp;
  if SOCKET_ERROR= connect(pskt^, @siTo, sizeof(siTo)) then
  begin
    iErr := WsaGetLastError;
    if (iErr<>997)and(iErr<>10035) then
    begin
      Txt_AppendMsg(now, 'zc_'+datetostr(now)+'_TCP_err.txt',
        'connect _iSktIdx - WsaGetLastError : '+inttostr(_iSktIdx)+' - '+inttostr(iErr) );
      ShowMsg('connect _iSktIdx - WsaGetLastError : '+inttostr(_iSktIdx)+' - '+inttostr(iErr));

      iLen := sizeof(TSockAddrIn);
      if SOCKET_ERROR =getsockname(pskt^, PSockAddr(@siErr), iLen) then
        ShowMsg('getsockname err : '+inttostr(WsaGetLastError))
      else
        ShowMsg('getsockname  : '+inttostr(ntohs(siErr.sin_port))+' - '+inet_ntoa(TInAddr(siErr.sin_addr)));
    end;
  end;
end;

#18


忘了说 16楼 我执行的命令是 “netstat -a -p tcp”

#19



// 取得 socket 地址
  pskt := @FzcSkts.Fskts[_iSktIdx];

// *** ***
// 关闭 socket  
  CloseSocket(pskt^); 
  pskt^ := INVALID_SOCKET;

不懂delphi,不过想问楼主一句。这三行代码的意思,是否和我下面C++的代码一样。

SOCKET *sock = &socks[idx];
closesocket(*sock);
*sock = INVALID_SOCKET;

如果是的话,应该不会出现你说的那个问题的吧。

话又说回来,你那个netstat的结果是全部的结果,还是一屏幕的结果?

#20


有bug,我的回复不见了?

#21


引用 19 楼  的回复:
这三行代码的意思,是否和我下面C++的代码一样。

一样

引用 19 楼  的回复:
你那个netstat的结果是全部的结果,还是一屏幕的结果?

全部~ 我是结果保存到 txt的

#22


引用 21 楼  的回复:
引用 19 楼 的回复:
这三行代码的意思,是否和我下面C++的代码一样。

一样


引用 19 楼 的回复:
你那个netstat的结果是全部的结果,还是一屏幕的结果?

全部~ 我是结果保存到 txt的

再等等别人的回复吧,没看出有啥问题,帮你顶一下。

#23


之前忘了说个事,我是在 XP上写的,测试的,我是做成 服务应用程序的。
会有 100个目标,时间久了10055 的问题。

相同代码,相同目标ip、port ,置于 2003 ,12+小时也没错误报出。不知何解??

#24


该回复于2012-06-08 10:09:31被版主删除

#25


你在 closesocket(s )前调用
shutdown(s,SD_BOTH)
就什么问题也不会发生了
具体原因是你没吃透TCP/IP的运行原理
服务器操作系统是为后台运行优化的,保留的不可分片内存和端口段都要比桌面WIN系统多
因此一般不容易发生端口耗尽

#26


楼上的朋友,能解释一下为什么不shutdown就会10055吗?

#27


引用 25 楼  的回复:
你在 closesocket(s )前调用
shutdown(s,SD_BOTH)
就什么问题也不会发生了
具体原因是你没吃透TCP/IP的运行原理
服务器操作系统是为后台运行优化的,保留的不可分片内存和端口段都要比桌面WIN系统多
因此一般不容易发生端口耗尽

这个 经试验 ,我加了 “shutdown(s,SD_BOTH)” ,并不是“什么问题也不会发生了”,只是时间变得长了...
20120612 13:00 开始跑程序 ,至 2012-6-12 20:51:55 出现 10055 。

我确实没有 吃透TCP/IP的运行原理,有讲 这个问题相关的 资料能提供给我学习下么??

#28


我自己最开始学习VC的时候,
写过你一样原理的TCP端口测试代码
而且当初也出现过和你一样的问题
而且我当时的并发数量好象是1000个,比你多10倍
可以负责的告诉你
出现失败的原因100%是shutdown没有被正确使用
我自己的代码在添加了SHUTDOWN之后就完全解决了

如果你在CLOSESOCKET前调用了SHUTDOWN,
并检测了SOCKET创建的返回值
但是你这套测试代码还是出问题
那你还是检查你自己的代码在什么地方是不是发生了泄露或者其他什么的吧

具体原因三言两语难说清楚
Richard stevens 写的 TCP/IP协议卷 1-3 看一遍,就知道了


#29


bind 这个没必要, closesocket 后进行shutdown

#30


TCP缓冲区被lock了。

#31


引用 29 楼 fishion 的回复:
closesocket 后进行shutdown

之后shutdown??

引用 30 楼 vieri_ch 的回复:
TCP缓冲区被lock了。

这个... 知道是这个错误啊,就是要解决它啊

#32


各位好心人,我把代码写成 vc6 的了,于此处下载:  http://download.csdn.net/detail/okmnjizc/4370951 帮忙看一下吧~ 十分感谢。

ps : 有时间的好心人可以帮忙测一下。(我是这样测的 ,在 xp下,这个程序放在两个目录下,因为写txt没做互斥,然后分别运行 ,差不多1小时左右就有10055了)

#33


问题原因找到了,但是我很好奇为什么一定要用这种方式来判断端口的存活状态了?

#34


引用 33 楼  的回复:
问题原因找到了,

是啥原因呢?

引用 33 楼  的回复:
但是我很好奇为什么一定要用这种方式来判断端口的存活状态了?

∵我不知道其他 更好的方式啊....

#35


用 connect连接,再用WSAWaitForMultipleEvents等待事件 ,结果一样坑爹,
但是TCP连接部分 更清爽,_tcp_WSAEventSelect_vc6.rar 代码 :  http://download.csdn.net/detail/okmnjizc/4372366  还是期待好心人帮忙看看。

ps : 还是期待好人帮忙看看测测。我将程序放于某处,连续双击打开了12次,即12个本程序一起跑,2分钟左右吧,应该肯定不到5分钟,XP 就connect 10055了...

介于 28 楼(danscort2000 兄) 的回复,我十分想知道,我该怎么改代码才能在XP里不10035 。
(TCP/IP协议卷 还在看中....比较乱.....)

#36


Listen函数指定等待连接的最大队列长度,默认值是5

#37


兄弟,我也关注你这个帖子好久了,要不你试试“优雅关闭”吧。



#include <winsock2.h>
#include <stdio.h>

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

int __cdecl main() {

    //----------------------
    // Declare and initialize variables.
    WSADATA wsaData;
    int iResult;

    SOCKET ConnectSocket;
    struct sockaddr_in clientService; 

    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
  
    //----------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != NO_ERROR) {
      printf("WSAStartup failed: %d\n", iResult);
      return 1;
    }

    //----------------------
    // Create a SOCKET for connecting to server
    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ConnectSocket == INVALID_SOCKET) {
        printf("Error at socket(): %ld\n", WSAGetLastError() );
        WSACleanup();
        return 1;
    }

    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port of the server to be connected to.
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
    clientService.sin_port = htons( 27015 );

    //----------------------
    // Connect to server.
    iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );
    if ( iResult == SOCKET_ERROR) {
        closesocket (ConnectSocket);
        printf("Unable to connect to server: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());

    } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

#38


跟MSDN上的例子一样,先shutdown,在一直recv到0或error,最后closesocket。

#39


引用 38 楼  的回复:
跟MSDN上的例子一样,先shutdown,在一直recv到0或error,最后closesocket。

如何 优雅?
我现在么有 send 和recv 。
我现在的顺序是 WSASocket-->WSAEventSelect-->connect-->shutdown-->closesocket 。xp上开了 20个,1分钟左右,10055出现 (是用的35楼的注释掉了setsockopt SO_LINGER 后的代码)

#40


关注一下!帮顶!

#41


楼主,我下载了你的代码,ConnectEx不是你那么用的。 你用普通的socket,和connect不行么? 非要搞异步的?

#42


引用 41 楼  的回复:
楼主,我下载了你的代码,ConnectEx不是你那么用的。 你用普通的socket,和connect不行么? 非要搞异步的?

35楼的没有 ConnectEx 是 connect ~~~ 你看看呢~~
还有 ,ConnectEx 是怎么用的?

#43


你在CSDN上传的那份代码就是用的ConnectEx。

#44


晕啊  35楼 又有一份啊 ,_tcp_WSAEventSelect_vc6.rar :


if (SOCKET_ERROR == connect(g_skts[_iIdx], (sockaddr*)&siConn, sizeof(siConn)))
{
int iErr = WSAGetLastError();
if ((iErr != 997)&&(iErr != 10035))
{
sprintf(bufErr, "connect(%d) SOCKET_ERROR : %d", _iIdx, iErr);
zcPrintErr1(&bufErr[0]);
return;
}
}
else
{
printf("connect(%d) OK", _iIdx);
}




再有 ,你说“ConnectEx不是你那么用的”,那应该是怎么用的??指教下

#45


引用 44 楼  的回复:
晕啊 35楼 又有一份啊 ,_tcp_WSAEventSelect_vc6.rar :


C/C++ code

    if (SOCKET_ERROR == connect(g_skts[_iIdx], (sockaddr*)&amp;siConn, sizeof(siConn)))
    {
        int iErr = WSAGetLastError();
  ……

ConnectEx是异步的,得用iocp获取异步操作的结果,想你那样,默认15秒之内一定会连接成功是不对的。
你应该在GetQueuedCompletionStatus里面把连接成功的套接字关掉,并重新连接一次。

#46


引用 45 楼  的回复:
ConnectEx是异步的,得用iocp获取异步操作的结果,想你那样,默认15秒之内一定会连接成功是不对的。

我还以为是函数使用上有问题呢 ... 这个是程序思路上的问题,以后可能不这样弄...

但是话说回来,不能这样弄么?在15秒内连不上,我就当它断线不行么,只不过可能程序得到的结果不准确而已 。相关的api函数 应该支持这种还未连上 就断开彻底放弃连接 的情况的吧??这种情况不会就是导致10055的最大原因?? 我现在就想解决 xp下 10055 的事情 ...

#47


引用 44 楼  的回复:
晕啊 35楼 又有一份啊 ,_tcp_WSAEventSelect_vc6.rar :


C/C++ code

    if (SOCKET_ERROR == connect(g_skts[_iIdx], (sockaddr*)&amp;siConn, sizeof(siConn)))
    {
        int iErr = WSAGetLastError();
  ……


既然你都用connect了,这是个阻塞函数,不成功或者出错不会返回的,你再用WSAEventSelect就没有意义了。

#48



#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")

#define DEFAULT_BUFLEN 512
#define SOCK_IP "119.75.218.77"
#define SOCK_PORT 80
#define MAX_NUM 100
#define INTERVAL 5

int test_connect()
{
char *sendbuf = "this is a test";
SOCKET ConnectSocket;
struct sockaddr_in clientService; 

char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = 0, iResult;

ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError() );
WSACleanup();
return 1;
}

clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(SOCK_IP);
clientService.sin_port = htons(SOCK_PORT);

iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );
if ( iResult == SOCKET_ERROR) {
closesocket (ConnectSocket);
printf("Unable to connect to server: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}

iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}

iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}

do {

iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
/*printf("Connection closed\n")*/;
else
printf("recv failed: %d\n", WSAGetLastError());

} while( iResult > 0 );

closesocket(ConnectSocket);
return 0;
}

int _tmain(int argc, _TCHAR* argv[]) {
WSADATA wsaData;
int iResult;

iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}

while (1) {
bool flag = true;
for (int i = 0; i < MAX_NUM; i++) {
if (0 != test_connect())
flag = false;
}
if (flag)
printf("all connnect success\n");
Sleep(INTERVAL * 1000);
}
WSACleanup();

return 0;
}


你试试这个吧,楼主。 我测了10分钟,没有10055,但是会出现10054,不过很可能是防火墙发的reset,connect都是成功的。
其实这个方法并不好,应该一个线程一个套接字,或者搞成异步IOCP,不过那个有点耗时,我懒得弄了。

#49


引用 47 楼  的回复:
既然你都用connect了,这是个阻塞函数,不成功或者出错不会返回的,你再用WSAEventSelect就没有意义了。

用了 WSAEventSelect ,就是 非阻塞 了啊 ,大哥!!!!!
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx

With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are three possible scenarios:

•Use ......
•......
•If the application is using WSAEventSelect to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
WSAEWOULDBLOCK The socket is marked as nonblocking and the connection cannot be completed immediately.
 

#50


引用 48 楼  的回复:
C/C++ code


#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")

#define DEFAULT_BUFLEN 512
#define SOCK_IP "119.75.218.77"
#define SOCK_PORT 80
#define MAX_NUM 100
……

你这个,主要是 你的顺序是 conn1-->close1-->conn2-->close2-->... 这样的顺序的一个接着一个的进行的。你这个程序在任一时间都最多只会有一个TCP连接存在...
我的是 一下子连接数个目标,不是一个 思路啊......

#1


怀疑是你关闭socket问题,看看这个行不行。

void __fastcall ForceCloseSocket(SOCKET &s,bool bClose)
{
  bool bDontLinger = false;
  setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(char *)&bDontLinger,sizeof(bool));

  linger InternalLinger;
  InternalLinger.l_onoff = 1;
  InternalLinger.l_linger = 0;

  setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&InternalLinger,sizeof(linger));

  if(bClose)
  {
    closesocket(s);
    s = INVALID_SOCKET;
  }
}

#2


或者你可以DisconnectEx然后重用socket句柄
http://kasicass.blog.163.com/blog/static/39561920084884555205/

#3


setsockopt(SOCKET, SOL_SOCKET, SO_REUSERADDR, ...);
试试

#4


to 3楼 VisualEleven
  经测试,一样

to 1楼 gibsonboy
  这个不就是设置 TIME_Wait 会有用么?试试去~

#5


引用 1 楼  的回复:
怀疑是你关闭socket问题,看看这个行不行。

刚完成的测试结果,还是一样啊~

#6


外行说两句:
1、从叙述看运行开始是没问题的,3小时候出现,那么就是累积的,缓冲区是否是已经累计了一些错误信息。或某一刻,链接过多给出信息故,累积出来的。
2、程序中一些功能函数添加判断,比如是否关闭成功了等等。

#7


引用 6 楼  的回复:
外行说两句:
1、从叙述看运行开始是没问题的,3小时候出现,那么就是累积的,缓冲区是否是已经累计了一些错误信息。或某一刻,链接过多给出信息故,累积出来的。
2、程序中一些功能函数添加判断,比如是否关闭成功了等等。

WsaSocket setsockopt bind WsaEventSelect connect
都加了 显示错误信息 ,直到 10055之前都么有错误信息显示出来

#8


你确定你安全释放socket吗?任务管理器的句柄数如何?

没问题的话看看这个  http://worldoffang.ycool.com/post.3676750.html

#9


引用 8 楼  的回复:
你确定你安全释放socket吗?任务管理器的句柄数如何?

没问题的话看看这个 http://worldoffang.ycool.com/post.3676750.html

何谓 “安全释放”? 
“句柄数” 倒是没注意,得看看

#10


觉得你的步骤怪怪的
应该是socket -> connect -> closesocket
bind是不必要的,bind端口0更是没必要
还有为什么closesocket放第一步?
猜是closesocket处理不好

另外在控制台输入命令netstat -an看一下

#11


本帖最后由 oyljerry 于 2012-06-08 09:35:08 编辑
引用 8 楼  的回复:
你确定你安全释放socket吗?任务管理器的句柄数如何?

没问题的话看看这个 http://worldoffang.ycool.com/post.3676750.html

貌似"句柄数"确实在增加,不见减少。怎么“安全释放”?  

#12


socket(),函数初始化一次,就有了一个句柄了,对应的,用closesocket关闭了,就没事了,需要注意的就是,匹配好初始化与关闭的代码

#13


引用 10 楼  的回复:
还有为什么closesocket放第一步?

因为我 第一步 关闭的 socket 是上次创建的socket ,
然后这次创建的 socket ,到下次第一步时关闭。

引用 10 楼  的回复:
觉得你的步骤怪怪的
应该是socket -> connect -> closesocket
bind是不必要的,bind端口0更是没必要

我现在吧 bind 去掉了,轮到 connect 返回10055了

#14


把出现10055时,netstat的结果贴出来。
最好把代码也贴上来。
现在的描述很难回答。

#15


http://msdn.microsoft.com/en-us/library/windows/desktop/ms737582(v=vs.85).aspx
看一下CloseSocket的官方文档,仔细看标记NOTE的文本,怎么释放socket。

另外也可以看这个 http://hi.baidu.com/info_sec/blog/item/61978eb7608a5af531add15b.html

#16


引用 14 楼  的回复:
把出现10055时,netstat的结果贴出来。
最好把代码也贴上来。
现在的描述很难回答。


Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    opos1:http             opos1:0                LISTENING
  TCP    opos1:epmap            opos1:0                LISTENING
  TCP    opos1:microsoft-ds     opos1:0                LISTENING
  TCP    opos1:1079             opos1:0                LISTENING
  TCP    opos1:2869             opos1:0                LISTENING
  TCP    opos1:3306             opos1:0                LISTENING
  TCP    opos1:4783             opos1:0                LISTENING
  TCP    opos1:18386            opos1:0                LISTENING
  TCP    opos1:33673            opos1:0                LISTENING
  TCP    opos1:1049             opos1:0                LISTENING
  TCP    opos1:netbios-ssn      opos1:0                LISTENING
  TCP    opos1:microsoft-ds     192.168.3.103:1034     ESTABLISHED
  TCP    opos1:1038             UNKNOWN-110-75-161-145.aliyun.com:16000  ESTABLI
SHED
  TCP    opos1:3077             78.129.163.10:http     SYN_SENT
  TCP    opos1:3111             hosted-by.leaseweb.com:http  SYN_SENT
  TCP    opos1:3113             hosted-by.leaseweb.com:http  SYN_SENT
  TCP    opos1:3114             87.117.203.6:http      SYN_SENT
  TCP    opos1:3172             180.189.157.90:http    SYN_SENT
  TCP    opos1:3173             180.189.157.92:http    SYN_SENT
  TCP    opos1:3185             hosted-by.leaseweb.com:http  SYN_SENT
  TCP    opos1:3195             host-219-235-2-79.iphost.gotonets.com:http  SYN_
SENT
  TCP    opos1:3201             50.22.192.196-static.reverse.softlayer.com:http
 SYN_SENT
  TCP    opos1:3203             50.22.74.3-static.reverse.softlayer.com:http  SY
N_SENT

#17


引用 14 楼  的回复:
最好把代码也贴上来。
现在的描述很难回答。

代码是 Delphi 的,能看的就帮看看吧

begin
// 取得 socket 地址
  pskt := @FzcSkts.Fskts[_iSktIdx];

// *** ***
// 关闭 socket  
  CloseSocket(pskt^); 
  pskt^ := INVALID_SOCKET;

// *** ***
// 重新获取 socket值
  pskt^ := WsaSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nil, 0, 0{WSA_FLAG_OVERLAPPED});
  if pskt^=INVALID_SOCKET then
  begin
    iErr := WsaGetLastError;
    Txt_AppendMsg(now, 'zc_'+datetostr(now)+'_TCP_err.txt',
      'WsaSocket INVALID_SOCKET : '+inttostr(iErr) );
    ShowMsg('WsaSocket INVALID_SOCKET : '+inttostr(iErr));
  end;

// *** ***
// socket 事件关联
  if 0<>WsaEventSelect(pskt^, FzcSkts.FhEvents[_iSktIdx], FD_CONNECT) then
  begin
    iErr := WsaGetLastError;
    Txt_AppendMsg(now, 'zc_'+datetostr(now)+'_TCP_err.txt',
      'WsaEventSelect err : '+inttostr(iErr) );
    ShowMsg('WsaEventSelect err : '+inttostr(iErr));
  end;

// *** ***
// connect
  ZeroMemory(@siTo, sizeof(TSOCKADDRIN));
  siTo.sin_family := AF_INET;
  siTo.sin_port := htons(_p.port_i);
  siTo.sin_addr.S_addr := _p.iDnsIp;
  if SOCKET_ERROR= connect(pskt^, @siTo, sizeof(siTo)) then
  begin
    iErr := WsaGetLastError;
    if (iErr<>997)and(iErr<>10035) then
    begin
      Txt_AppendMsg(now, 'zc_'+datetostr(now)+'_TCP_err.txt',
        'connect _iSktIdx - WsaGetLastError : '+inttostr(_iSktIdx)+' - '+inttostr(iErr) );
      ShowMsg('connect _iSktIdx - WsaGetLastError : '+inttostr(_iSktIdx)+' - '+inttostr(iErr));

      iLen := sizeof(TSockAddrIn);
      if SOCKET_ERROR =getsockname(pskt^, PSockAddr(@siErr), iLen) then
        ShowMsg('getsockname err : '+inttostr(WsaGetLastError))
      else
        ShowMsg('getsockname  : '+inttostr(ntohs(siErr.sin_port))+' - '+inet_ntoa(TInAddr(siErr.sin_addr)));
    end;
  end;
end;

#18


忘了说 16楼 我执行的命令是 “netstat -a -p tcp”

#19



// 取得 socket 地址
  pskt := @FzcSkts.Fskts[_iSktIdx];

// *** ***
// 关闭 socket  
  CloseSocket(pskt^); 
  pskt^ := INVALID_SOCKET;

不懂delphi,不过想问楼主一句。这三行代码的意思,是否和我下面C++的代码一样。

SOCKET *sock = &socks[idx];
closesocket(*sock);
*sock = INVALID_SOCKET;

如果是的话,应该不会出现你说的那个问题的吧。

话又说回来,你那个netstat的结果是全部的结果,还是一屏幕的结果?

#20


有bug,我的回复不见了?

#21


引用 19 楼  的回复:
这三行代码的意思,是否和我下面C++的代码一样。

一样

引用 19 楼  的回复:
你那个netstat的结果是全部的结果,还是一屏幕的结果?

全部~ 我是结果保存到 txt的

#22


引用 21 楼  的回复:
引用 19 楼 的回复:
这三行代码的意思,是否和我下面C++的代码一样。

一样


引用 19 楼 的回复:
你那个netstat的结果是全部的结果,还是一屏幕的结果?

全部~ 我是结果保存到 txt的

再等等别人的回复吧,没看出有啥问题,帮你顶一下。

#23


之前忘了说个事,我是在 XP上写的,测试的,我是做成 服务应用程序的。
会有 100个目标,时间久了10055 的问题。

相同代码,相同目标ip、port ,置于 2003 ,12+小时也没错误报出。不知何解??

#24


该回复于2012-06-08 10:09:31被版主删除

#25


你在 closesocket(s )前调用
shutdown(s,SD_BOTH)
就什么问题也不会发生了
具体原因是你没吃透TCP/IP的运行原理
服务器操作系统是为后台运行优化的,保留的不可分片内存和端口段都要比桌面WIN系统多
因此一般不容易发生端口耗尽

#26


楼上的朋友,能解释一下为什么不shutdown就会10055吗?

#27


引用 25 楼  的回复:
你在 closesocket(s )前调用
shutdown(s,SD_BOTH)
就什么问题也不会发生了
具体原因是你没吃透TCP/IP的运行原理
服务器操作系统是为后台运行优化的,保留的不可分片内存和端口段都要比桌面WIN系统多
因此一般不容易发生端口耗尽

这个 经试验 ,我加了 “shutdown(s,SD_BOTH)” ,并不是“什么问题也不会发生了”,只是时间变得长了...
20120612 13:00 开始跑程序 ,至 2012-6-12 20:51:55 出现 10055 。

我确实没有 吃透TCP/IP的运行原理,有讲 这个问题相关的 资料能提供给我学习下么??

#28


我自己最开始学习VC的时候,
写过你一样原理的TCP端口测试代码
而且当初也出现过和你一样的问题
而且我当时的并发数量好象是1000个,比你多10倍
可以负责的告诉你
出现失败的原因100%是shutdown没有被正确使用
我自己的代码在添加了SHUTDOWN之后就完全解决了

如果你在CLOSESOCKET前调用了SHUTDOWN,
并检测了SOCKET创建的返回值
但是你这套测试代码还是出问题
那你还是检查你自己的代码在什么地方是不是发生了泄露或者其他什么的吧

具体原因三言两语难说清楚
Richard stevens 写的 TCP/IP协议卷 1-3 看一遍,就知道了


#29


bind 这个没必要, closesocket 后进行shutdown

#30


TCP缓冲区被lock了。

#31


引用 29 楼 fishion 的回复:
closesocket 后进行shutdown

之后shutdown??

引用 30 楼 vieri_ch 的回复:
TCP缓冲区被lock了。

这个... 知道是这个错误啊,就是要解决它啊

#32


各位好心人,我把代码写成 vc6 的了,于此处下载:  http://download.csdn.net/detail/okmnjizc/4370951 帮忙看一下吧~ 十分感谢。

ps : 有时间的好心人可以帮忙测一下。(我是这样测的 ,在 xp下,这个程序放在两个目录下,因为写txt没做互斥,然后分别运行 ,差不多1小时左右就有10055了)

#33


问题原因找到了,但是我很好奇为什么一定要用这种方式来判断端口的存活状态了?

#34


引用 33 楼  的回复:
问题原因找到了,

是啥原因呢?

引用 33 楼  的回复:
但是我很好奇为什么一定要用这种方式来判断端口的存活状态了?

∵我不知道其他 更好的方式啊....

#35


用 connect连接,再用WSAWaitForMultipleEvents等待事件 ,结果一样坑爹,
但是TCP连接部分 更清爽,_tcp_WSAEventSelect_vc6.rar 代码 :  http://download.csdn.net/detail/okmnjizc/4372366  还是期待好心人帮忙看看。

ps : 还是期待好人帮忙看看测测。我将程序放于某处,连续双击打开了12次,即12个本程序一起跑,2分钟左右吧,应该肯定不到5分钟,XP 就connect 10055了...

介于 28 楼(danscort2000 兄) 的回复,我十分想知道,我该怎么改代码才能在XP里不10035 。
(TCP/IP协议卷 还在看中....比较乱.....)

#36


Listen函数指定等待连接的最大队列长度,默认值是5

#37


兄弟,我也关注你这个帖子好久了,要不你试试“优雅关闭”吧。



#include <winsock2.h>
#include <stdio.h>

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

int __cdecl main() {

    //----------------------
    // Declare and initialize variables.
    WSADATA wsaData;
    int iResult;

    SOCKET ConnectSocket;
    struct sockaddr_in clientService; 

    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
  
    //----------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != NO_ERROR) {
      printf("WSAStartup failed: %d\n", iResult);
      return 1;
    }

    //----------------------
    // Create a SOCKET for connecting to server
    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ConnectSocket == INVALID_SOCKET) {
        printf("Error at socket(): %ld\n", WSAGetLastError() );
        WSACleanup();
        return 1;
    }

    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port of the server to be connected to.
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
    clientService.sin_port = htons( 27015 );

    //----------------------
    // Connect to server.
    iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );
    if ( iResult == SOCKET_ERROR) {
        closesocket (ConnectSocket);
        printf("Unable to connect to server: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());

    } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

#38


跟MSDN上的例子一样,先shutdown,在一直recv到0或error,最后closesocket。

#39


引用 38 楼  的回复:
跟MSDN上的例子一样,先shutdown,在一直recv到0或error,最后closesocket。

如何 优雅?
我现在么有 send 和recv 。
我现在的顺序是 WSASocket-->WSAEventSelect-->connect-->shutdown-->closesocket 。xp上开了 20个,1分钟左右,10055出现 (是用的35楼的注释掉了setsockopt SO_LINGER 后的代码)

#40


关注一下!帮顶!

#41


楼主,我下载了你的代码,ConnectEx不是你那么用的。 你用普通的socket,和connect不行么? 非要搞异步的?

#42


引用 41 楼  的回复:
楼主,我下载了你的代码,ConnectEx不是你那么用的。 你用普通的socket,和connect不行么? 非要搞异步的?

35楼的没有 ConnectEx 是 connect ~~~ 你看看呢~~
还有 ,ConnectEx 是怎么用的?

#43


你在CSDN上传的那份代码就是用的ConnectEx。

#44


晕啊  35楼 又有一份啊 ,_tcp_WSAEventSelect_vc6.rar :


if (SOCKET_ERROR == connect(g_skts[_iIdx], (sockaddr*)&siConn, sizeof(siConn)))
{
int iErr = WSAGetLastError();
if ((iErr != 997)&&(iErr != 10035))
{
sprintf(bufErr, "connect(%d) SOCKET_ERROR : %d", _iIdx, iErr);
zcPrintErr1(&bufErr[0]);
return;
}
}
else
{
printf("connect(%d) OK", _iIdx);
}




再有 ,你说“ConnectEx不是你那么用的”,那应该是怎么用的??指教下

#45


引用 44 楼  的回复:
晕啊 35楼 又有一份啊 ,_tcp_WSAEventSelect_vc6.rar :


C/C++ code

    if (SOCKET_ERROR == connect(g_skts[_iIdx], (sockaddr*)&amp;siConn, sizeof(siConn)))
    {
        int iErr = WSAGetLastError();
  ……

ConnectEx是异步的,得用iocp获取异步操作的结果,想你那样,默认15秒之内一定会连接成功是不对的。
你应该在GetQueuedCompletionStatus里面把连接成功的套接字关掉,并重新连接一次。

#46


引用 45 楼  的回复:
ConnectEx是异步的,得用iocp获取异步操作的结果,想你那样,默认15秒之内一定会连接成功是不对的。

我还以为是函数使用上有问题呢 ... 这个是程序思路上的问题,以后可能不这样弄...

但是话说回来,不能这样弄么?在15秒内连不上,我就当它断线不行么,只不过可能程序得到的结果不准确而已 。相关的api函数 应该支持这种还未连上 就断开彻底放弃连接 的情况的吧??这种情况不会就是导致10055的最大原因?? 我现在就想解决 xp下 10055 的事情 ...

#47


引用 44 楼  的回复:
晕啊 35楼 又有一份啊 ,_tcp_WSAEventSelect_vc6.rar :


C/C++ code

    if (SOCKET_ERROR == connect(g_skts[_iIdx], (sockaddr*)&amp;siConn, sizeof(siConn)))
    {
        int iErr = WSAGetLastError();
  ……


既然你都用connect了,这是个阻塞函数,不成功或者出错不会返回的,你再用WSAEventSelect就没有意义了。

#48



#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")

#define DEFAULT_BUFLEN 512
#define SOCK_IP "119.75.218.77"
#define SOCK_PORT 80
#define MAX_NUM 100
#define INTERVAL 5

int test_connect()
{
char *sendbuf = "this is a test";
SOCKET ConnectSocket;
struct sockaddr_in clientService; 

char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = 0, iResult;

ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError() );
WSACleanup();
return 1;
}

clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(SOCK_IP);
clientService.sin_port = htons(SOCK_PORT);

iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );
if ( iResult == SOCKET_ERROR) {
closesocket (ConnectSocket);
printf("Unable to connect to server: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}

iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}

iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}

do {

iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
/*printf("Connection closed\n")*/;
else
printf("recv failed: %d\n", WSAGetLastError());

} while( iResult > 0 );

closesocket(ConnectSocket);
return 0;
}

int _tmain(int argc, _TCHAR* argv[]) {
WSADATA wsaData;
int iResult;

iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}

while (1) {
bool flag = true;
for (int i = 0; i < MAX_NUM; i++) {
if (0 != test_connect())
flag = false;
}
if (flag)
printf("all connnect success\n");
Sleep(INTERVAL * 1000);
}
WSACleanup();

return 0;
}


你试试这个吧,楼主。 我测了10分钟,没有10055,但是会出现10054,不过很可能是防火墙发的reset,connect都是成功的。
其实这个方法并不好,应该一个线程一个套接字,或者搞成异步IOCP,不过那个有点耗时,我懒得弄了。

#49


引用 47 楼  的回复:
既然你都用connect了,这是个阻塞函数,不成功或者出错不会返回的,你再用WSAEventSelect就没有意义了。

用了 WSAEventSelect ,就是 非阻塞 了啊 ,大哥!!!!!
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx

With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are three possible scenarios:

•Use ......
•......
•If the application is using WSAEventSelect to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
WSAEWOULDBLOCK The socket is marked as nonblocking and the connection cannot be completed immediately.
 

#50


引用 48 楼  的回复:
C/C++ code


#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")

#define DEFAULT_BUFLEN 512
#define SOCK_IP "119.75.218.77"
#define SOCK_PORT 80
#define MAX_NUM 100
……

你这个,主要是 你的顺序是 conn1-->close1-->conn2-->close2-->... 这样的顺序的一个接着一个的进行的。你这个程序在任一时间都最多只会有一个TCP连接存在...
我的是 一下子连接数个目标,不是一个 思路啊......