基于select模式的 一个工作线程主线程在接受客户端的连接,工作线程在处理数据能否在以下代码基础上实现一个功能:有客户端连接后,就接受数据,然后 写到磁盘中,注:保存磁盘有讲究, 文件名必须是1001,1002,1003,以此类推。     CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);     
         while (TRUE)   
         {               // Accept a connection     
             sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);     
             printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));     
             // Add socket to g_CliSocketArr     
             g_CliSocketArr[g_iTotalConn++] = sClient;   
         }     
     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); 
             }                     // We only care read event 
             ret = select(0, &fdread, NULL, NULL, &tv); 
             if (ret == 0) 
             {       // Time expired 
                 continue; 
             } 
             for (i = 0; i < g_iTotalConn; i++) 
             { 
                 if (FD_ISSET(g_CliSocketArr, &fdread)) 
                   {         // A read event happened on g_CliSocketArr 
                       ret = recv(g_CliSocketArr, szMessage, MSGSIZE, 0); 
                       if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)) 
                         { 
                             // Client socket closed           
                             printf("Client socket %d closed.\n", g_CliSocketArr); 
                             closesocket(g_CliSocketArr); 
                             if (i < g_iTotalConn - 1) 
                             { 
                                 g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn]; 
                             } 
                         } 
                         else 
                         { 
                               // We received a message from client 
                               szMessage[ret] = '\0'; 
                               send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0); 
                         } 
                   } //if 
             }//for 
         }//while     
         return 0; 
     } 

解决方案 »

  1.   

    #include <fstream>
    using namespace std;DWORD WINAPI WorkerThread(LPVOID lpParam)
    {
       ...
                    else
                    {
                        // We received a message from client                    ofstream filestream;
                        char name[4];
                        sprintf(name, "%d", i);
                        filestream.open("name", ios::out|ios::app);
                        filestream.write(szMessage, ret);
                        filestream.close();                    szMessage[ret] = '\0';
                        send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0);
                    }
      ...
    }
    如果是一个连接对应一个文件的话,我想这样就可以简单实现了。
    其他地方都省略了,你如果想改变文件名的基数就在sprintf那里动一下手脚就行了。
      

  2.   

    一个连接对应一个文件。 会不会有这样的问题:socket和磁盘文件对不上啊。。 假设一种完美的情况:10个socket都在线。开始发送数据给服务端。  g_CliSocketArr里的内容是不变的,因为socket都在。我们可以按扎 for循环中的下标,编号,  第0个socket 对应10001第一个对应10002
    但是一旦有个socket先下线了,那么 10个必然变成9个了。 顺序就混乱了。 for (i = 0; i < g_iTotalConn; i++) 
                 { 
                     if (FD_ISSET(g_CliSocketArr, &fdread)) 
                       {         // A read event happened on g_CliSocketArr 
                           ret = recv(g_CliSocketArr, szMessage, MSGSIZE, 0); 
                           if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)) 
                             { 
                                 // Client socket closed           
                                 printf("Client socket %d closed.\n", g_CliSocketArr); 
                                 closesocket(g_CliSocketArr); 
                                 if (i < g_iTotalConn - 1) 
                                 { 
                                     g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn]; 
                                 } 
                             } 
                             else 
                             { 
                                   // We received a message from client //保存到磁盘里
                                   szMessage[ret] = '\0'; 
                                   send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0); 
                             } 
                       } //if 
                 }//for 
      

  3.   

    我看你是有一个连接出了错就把最后一个放到出错的那个socket对应的位置上。
    要想一个socket对应一个文件,我想有两个简单的方法可以解决
    1.定义一个结构
    struct CLIENT{
      SOCKET sock;
      char   filename[4];
    };然后你数组里就不要存socket了直接存这个结构,
    socket与文件一一对应。
    2.可以使用map
    map<SCOKET, char*>
    同时建立一个保存文件名的数组,用map建立socket和文件名的关联。我认为第一个相对来讲好一点,因为如果以后你需要针对每个连接处理更多问题的时候可能需要添加更多的参数一类的内容。
    当然你把struct改成class是一样的。
      

  4.   


    多谢你了啊,呵呵这代码是来自网上,我只是想修改一下代码中有个bug, 如是最后一个套接字出错,竟然没有处理。不知道是我多想,还是 我猜错了