为什么不在线程里去做select检测呢?尽量简单化结构设计

解决方案 »

  1.   

    当可以时就不用select监测这个socket了,只有把数据都读完后,再把这个socket加到select监测可读集合中。这有使用select的例子,找MsgSend目录:
    http://download.csdn.net/detail/geoff08zhang/4571358
      

  2.   

    你这种方式加锁的话  多线程的优势已经没有了  一定要这样设计 那么每次返回的socket 你都需要FD_CLR再丢到线程池去收数据  线程中处理完成 发消息通知主线程 主线程在FD_SET进去 这样不需要锁 也不存在多个线程收同一个socket的数据 postmessage也不影响性能  多客户端的情况下 至少不耽误其他socket接收数据
      

  3.   


    线程池只有10个,可能有100个客户端,在线程池线程里要怎么样select呢?
      

  4.   

    100个客户端你  select? 把64连接上限自己拓展了不?
      

  5.   

    是linux的,用的pthread,发不了消息。
      

  6.   

    给你看个伪代码,希望能启发你。#define PORT 5200
    #define MSGSIZE 1024
    int g_iTotalConn = 0;
    SOCKET g_CliSocketArr[FD_SETSIZE];int main()
    {
    WSAStartup(0x0202, &wsaData); // 创建监听socket
    sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 绑定
    local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    local.sin_family = AF_INET;
    local.sin_port = htons(PORT);
    bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN)); // 监听
    listen(sListen, 3); // 创建工作者线程
    CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);  while (TRUE)
    {
    // 接受一个连接
    sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize); // 记录增加的套机子
    g_CliSocketArr[g_iTotalConn++] = sClient;
    }
    return 0;
    }DWORD WINAPI WorkerThread(LPVOID lpParam)
    {
    int i;
    fd_set fdread;
    int ret;
    struct timeval tv = {1, 0};
    char szMessage[MSGSIZE]; while (TRUE)
    {
    FD_ZERO( &fdread ); //清空结构体 for (i = 0; i < g_iTotalConn; i++)
    {
    FD_SET( g_CliSocketArr[i], &fdread ); //往结构体里增加套接字
    } //The select function returns the number of sockets meeting the conditions.
    ret = select( NULL, &fdread, NULL, NULL, &tv ); if ( ret == -1 )
    {
    // 没有任何连接
    ::Sleep(100);
    continue;
    }
    if ( ret == 0 )
    {
    // 超时
    continue;
    }
    for (i = 0; i < g_iTotalConn; i++)
    {
    //whether a socket is included in a set of socket descriptors.
    if ( FD_ISSET( g_CliSocketArr[i], &fdread ) )
    {
    ret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, 0); if ( ret == 0 ) // 客户端socket关闭了
    {
    DeleteSocket( g_CliSocketArr[i] );
    }
    else if ( ret == SOCKET_ERROR )
    {
    DeleteSocket( g_CliSocketArr[i] );
    }
    else if ( ret > 0 ) // 从客户端接受到信息了
    {
    szMessage[ret] = '\0';
    send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0);
    }
    }
    }
    } return 0;
    }void DeleteSocket(SOCKET sock)
    {
    closesocket( sock ); long i;
    for ( i=0; i<g_iTotalConn; i++ )
    {
    if ( sock == g_CliSocketArr[i] )
    {
    long j=i;
    while ( j<g_iTotalConn-1 )
    {
    g_CliSocketArr[j] = g_CliSocketArr[j+1];
    j++;
    }
    g_iTotalConn--;
    return;
    }
    }
    }
      

  7.   

    linux发不了消息 应该也有相关的方法可以通知主线程的吧...
      

  8.   

    每种IO模式都有自己的使用方式。
    select模型只适合单个线程,这由select函数本身的特性决定了,并且读写操作就该紧随其后。这是正确的使用方式。
    如果非要用多个线程去处理,不单效率没有提升,反而会带来其他的麻烦,如同步问题、处理次序问题等。
      

  9.   

    另外,其实select也可以多线程的,只不过多线程是分配socket的时候。多个socket多个线程处理。
      

  10.   


    IOCP就是啊。IOCP中,为了节省线程切换带来的资源消耗,采用LIFO的调度。
      

  11.   

    感觉是没用好,你select发现可读,直接去读,然后将数据塞入缓冲区(每个socket一个缓冲区),对这个数据的处理可以是另外开启线程,也可以是你即时处理(如果不耗时),只需要一个线程一直select就好了,当连接断开时,干掉对应的缓冲区不就可以了?
      

  12.   

    只要是数据没有读完,select都会有返回的。
      

  13.   

    windows下的话,可以开N个线程,每个线程单独执行select并负责一组accept到的socket(通常最大值64个)
      

  14.   

    搞两个队列撒,一个检测socket队列A,一个数据接收队列B,检测是把A中有数据的socket丢到B里面去,同时送线程收数据,线程收完数据负责把socket从B里面去除,在放回到A,这样就不存在你说的问题了撒,你只需要做好A B的放入放出互斥
      

  15.   

    我觉的select真不是这样用的。每次select处理后,该套接字应该已经从select里面剥离出去了。需要再次添加进来才可以。这个时间,该套接字的缓冲区数据应该你能够拿完了。下次你需要用新的缓冲区来收数据了。
      

  16.   

    windows下面,用什么实习这种东西?
      

  17.   


    有个MVP全球峰会,自己买机票搞签证,Microsoft包5天4夜食宿,我没去啊。
    下次有空了当旅游再去吧。
      

  18.   

    LZ你理解错了。select 模型对套接字的可读性进行轮询,select 函数返回之后会标识出有多少个套接字上面有数据到来了而已,但这时数据已经到达系统的底层,这时你只需要使用对应的套接字调用recv函数去把数据拿出来就可以,不同的套接字调用recv函数时只会将属于它自己的那部分数据拿出来,而不是你理解的会拿到别人的数据。
    你说的线程池无非就是当同时有多少个套接字上面有数据到来时就开多少个线程,然后线程函数里面用相应的套接字调用recv函数去拿数据。但即使这样你拿到的数据也仅仅是属于特定的那个套接字的。