两个测试:
1. 单线程, connect结合select超时连接50个一样的IP, 结果很正常, 50次select都没返回错误.
2. 多线程, connect结合select超时连接50个一样的IP, 开50个线程, 每个线程负责一个连接, 就会出现问题, 有些可以正常返回, 有些select会返回超时, 超时值设得很大也不行.请问是为什么, select在多个线程同时处于socket等待的时候是如何工作的?

解决方案 »

  1.   

    如果代码有问题,从原理上来说,不会出现你说的情况,多个线程select不同的连接,跟一个线程select多个不同的连接结果上没有什么区别
      

  2.   

    #include <WINSOCK2.H>
    #include <stdio.h>
    #include <windows.h>#pragma comment(lib, "ws2_32")long lCount = 0;
    long lThreadCount = 0;DWORD _stdcall proc(LPVOID lParam)
    {
        for (long i = 0; i < lThreadCount; i++)
        {
            SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);        u_long ul = 1;
            ioctlsocket(s, FIONBIO, &ul);        sockaddr_in addr = {0};
            addr.sin_family = AF_INET;
            addr.sin_addr.s_addr = inet_addr("127.0.0.1");
            addr.sin_port = htons(135);
            int iret = connect(s, (sockaddr*)&addr, sizeof(addr));        fd_set wfds = {0};
            FD_SET(s, &wfds);
            timeval timeout = {0};
            timeout.tv_sec = 3; // 3秒超时
            iret = select(0, NULL, &wfds, NULL, &timeout);        if (0 == iret)
            {
                printf("select timeout\n");
            }
            else if (0 > iret)
            {
                printf("select error\n");
            }
            else
            {
                printf("%d\n", ++lCount);
            }        closesocket(s);
        }    return 0;
    }void single()
    {
        lThreadCount = 500;
        CloseHandle(CreateThread(NULL, 0, proc, NULL, 0, NULL));
    }void multiple()
    {
        lThreadCount = 1;
        for (int i = 0; i < 500; i++)
        {
            CloseHandle(CreateThread(NULL, 0, proc, NULL, 0, NULL));
        }
    }void main()
    {
        WSADATA lpWSAData;
        WSAStartup(0x0202, &lpWSAData);    //single();
        multiple();    while (1);
    }不知道这样测试对不对
      

  3.   

    测试方法有问题single()时 select 总是串行执行的 ,多线程则是并行的。
    可以把所有socket都放在fd_set里, 一起select咋。
      

  4.   

    那这样测试的时候, 多线程为什么会有问题呢? select会超时.
      

  5.   

    程序写了真是蛮好的,简洁明了,看不出问题所在
    把timeout.tv_sec = 3; // 3秒超时  设置再短一点呢?
      

  6.   

    当异步connect还没有实际成功时,调用select必然超时你在multiple中并发调用500次connect,服务端响应会较慢
    而你在connect之后直接select,当然会出问题
      

  7.   

    当异步connect还没有实际成功时,调用select必然超时
    ==============
    可是延时设很大结果也是一样啊.
      

  8.   


    必然超时的意思是:即使在select操作阻塞期间,connect成功了,select也不会成功
      

  9.   

    设置超时长点, 是针对服务端响应会较慢, 慢它也有返回吧, 可是设超时大点为什么select还是不成功呢?
    其实这只是一个测试, 用本机的测试, 如果说上面是500个连接连同一台机有问题,但在实际应用的只是3,4十个连接, 而且是不同的IP,这个应该是不存在服务端响应慢的原因吧,但一样会会出现上述问题, 单线程逐一连接全部成功,而且connect返回很快,不会有什么延时, 但在多线程的时候, 设几十秒的延时也同样是失败!
      

  10.   

    connect 成功了再select ,你的多线程应该和单线程应该是一个意思,因为你每个线程对应一个socket
      

  11.   

    和你超时设置没有关系,MSDN讲的很清楚,Winsock的设计就是这样的,select要在connect成功之后再调用
    否则,返回超时,即使你超时时间设置成一年也没用
      

  12.   

    connect成功是什么意思? 异步connect怎么会立刻返回成功呢? 单线程也不是马上返回成功的吧. 但单线程工作得很好.
      

  13.   

    MSDN的意思会不会是指connect成功后, select会把socket过滤在writefds中, 而不是指connect成功后才调用select呢?
    connect的函数说明是中也指出, 
    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 the select function to determine the completion of the connection request by checking to see if the socket is writeable这个也不是在connect成功后用select吧.
      

  14.   

    ioctlsocket(s, FIONBIO, &ul); 
    多线程应该用阻塞模式,建议去掉这句,然后做一个大的循环,多线程的和单线程的不能用同一个线程函数,
    还有楼主创建多线程的方法是不对的,应该在循环创建的时候加一个小延时,比方说Sleep(100)
      

  15.   

    select为什么可以用来判断异步connect是否已成功?
    说明select能否成功与connect是否已成功是互相关联的!如果异步connect还没成功,select就一定不会成功
      

  16.   

    u_long ul = 1; 
    ioctlsocket(s, FIONBIO, &ul);int iret = connect(s, (sockaddr*)&addr, sizeof(addr)); //iret值确实不为0啊, 表示没成功吧fd_set wfds = {0}; 
    FD_SET(s, &wfds); 
    timeval timeout = {0}; 
    timeout.tv_sec = 3; // 3秒超时 
    iret = select(0, NULL, &wfds, NULL, &timeout); //但是select会成功select设置延时的作用不就是返回只要在用户设置的延时期间内有响应的socket, 它都会过滤在对应的子集内吗?
    select能判断异步connect成功, 并不表示connect马上成功吧, 只要connect在设置的延时内有回应, 
    select都会被它放到wfds集合中
      

  17.   

    CloseHandle(CreateThread(NULL, 0, proc, NULL, 0, NULL)); 能这么写吗?
    CreateThread ,不一定创建thread就立即运行并成功返回HANDLE , 为什么立即关闭?
    线程运行完成了?你去查看下MSDN吧?把所有的代码分开
    检测所有的返回值,别想当然
    while (1);  ???? 干什么用?
    死循环?
      

  18.   


    晕,异步connect是立即返回的,通常都返回SOCKET_ERROR,且GetLastError()=WSAEWOULDBLOCKTCP协议下调用select时首会先去查询socket是否已握手,若尚未握手,select不会试图等待connect完成,它会直接返回超时;若socket已握手,然后才会去查询socket是否被其他操作block中,这时候select才会根据超时参数进行等待所以MSDN才会说,select可以用来判断connect是否已经完成你调用异步connect后马上调用select,则select查询握手状态时,connect既可能刚刚完成了,也可能还未完成,所以你的select可能成功,也可能失败,就这么简单,和你设不设置超时没有关系
      

  19.   

    TCP协议下调用select时首会先去查询socket是否已握手,若尚未握手,select不会试图等待connect完成,它会直接返回超时;若socket已握手,然后才会去查询socket是否被其他操作block中,这时候select才会根据超时参数进行等待 所以MSDN才会说,select可以用来判断connect是否已经完成 你调用异步connect后马上调用select,则select查询握手状态时,connect既可能刚刚完成了,也可能还
    未完成,所以你的select可能成功,也可能失败,就这么简单,和你设不设置超时没有关系
    ==================如果select在connect后去查询它是否握手成功, "若尚未握手,select不会试图等待connect完成,它会直
    接返回超时", 似乎不管怎样都不太可能会成功吧, 因为网络是有延时的, 那select岂不是每次都失败? 但同
    样是connect后马上调用select, 为什么单线程又全部都成功呢? 如果调用select的时候, 就能确定已经
    connect成功了, 那还要select的延时来干什么呢, select这里的效果不是sleep, 而是判断socket在延时
    期间是否connect成功啊
      

  20.   

    1、单线程的connect很快就会成功,多线程并发的connect会受服务器相应能力的影响,不见得能很快成功2、select不仅仅是用在connect之后的,其他IO操作(recv、send等)之后也可能调用select,这时候select的超时参数就会起作用,因为socket是握手状态中,只是block了而已,select就会尝试等待
      

  21.   


    楼主报名吧!你得搞清楚select模型再试验啊呵呵
      

  22.   

    1、单线程的connect很快就会成功,多线程并发的connect会受服务器相应能力的影响,不见得能很快成功 2、select不仅仅是用在connect之后的,其他IO操作(recv、send等)之后也可能调用select,这时候select的超时参数就会起作用,因为socket是握手状态中,只是block了而已,select就会尝试等待
    ====================
    单线程很快, 是因为这是本机测试, 但是实际实用也有慢的情况, 一样都会全部成功!(单线程)
    异步connect返回也是WSAEWOULDBLOCK, select也会尝试去等待吧? 而且测试结果也表明, select并不是
    马上就返回, 而是超时时间过后才返回的. 更奇怪的是, 只要有一个超时, 后面跟着的就会全部超时, 比如第
    20个线程超时了, 那么第21个线程连接的即使是本机IP, 也会超时.(多线程)
      

  23.   

    问个问题WSAAsynSelet函数注册的事件怎么注销啊。
      

  24.   

    照你的程序select是成功了返回,失败了肯定是超时,你可以超时的时候WSAGetLastError()分析一下错误码,这样一味乱猜没什么意思
      

  25.   

    MSDN:
    To cancel all notification indicating that Windows Sockets should send no further messages related to network events on the socket, lEvent is set to zero.rc = WSAAsyncSelect(s, hWnd, 0, 0);不是猜测, 错误码早就看过了, select返回0是超时, 此时GetLastError是0, 操作成功完成
      

  26.   

    奥,那应该是并发的链接过多造成的。listen(m),监听队列设置的值过小。