2013-03-13 53 views
0

嗨我想在C++中编写一个服务器winsock以允许从PHP客户端代码连接。 PHP将从服务器请求数据,接收并关闭连接。但是,连接2-3次后,当再次发出PHP请求时,它挂在socket_read()处,页面继续加载,并且服务器未收到FD_ACCEPT事件。是否因为TIME_WAIT连接尚未关闭?任何关于代码改进的建议都会很好。服务器套接字只能连接几次(Winsock C++)

SOCKET s; 
SOCKADDR_IN from; 
int fromLen = sizeof(from); 
int port = 1111; 

int listenOnPort(int portNo) 
{ 
    WSAData w; 

    int error = WSAStartup(0x0202, &w); // fill in wsa info 

    if(error) 
    { 
     printError(5); 
     return 0; 
    } 

    if(w.wVersion != 0x0202) 
    { 
     printError(6); 
     WSACleanup(); 
     return 0; 
    } 

    SOCKADDR_IN addr; 
    SOCKET client; 

    addr.sin_family = AF_INET; 
    addr.sin_port = htons(portNo); 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 

    s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    if(s == INVALID_SOCKET) 
    { 
     printError(7); 
     return 0; 
    } 

    BOOL bOptVal = TRUE; 
    int bOptLen = sizeof (BOOL); 
    if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen) == SOCKET_ERROR) 
    { 
     printError(12); 
     return 0; 
    } 

    if(bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) 
    { 
     printError(8); 
     return 0; 
    } 

    if(listen(s, 1) == SOCKET_ERROR) //start listening 
    { 
     printError(13); 
     return 0; 
    } 

    //WSAAsyncSelect(s, hwnd, 1045, FD_READ | FD_CONNECT | FD_CLOSE | FD_ACCEPT); 

    cout << "Ready to accept connection, listening on port " << portNo << endl; 

    CreateThread(0,0, &listenForEvents, NULL, 0, 0); 

    //listenForEvents(); 

    return 1; //ok 
} 

DWORD WINAPI listenForEvents(void* lp) 
{ 
    HANDLE sockEv=CreateEvent(NULL,TRUE,FALSE,NULL); 
    if(WSAEventSelect(s,sockEv,FD_ACCEPT|FD_CONNECT| FD_READ | FD_CLOSE)==SOCKET_ERROR) 
     printError(9); 

    for(;;) { 
     if(WSAWaitForMultipleEvents(1,&sockEv,FALSE,INFINITE,FALSE)!=WSA_WAIT_EVENT_0) 
      printError(10); 

     WSANETWORKEVENTS wsaEvents={0}; 
     if(WSAEnumNetworkEvents(s,sockEv,&wsaEvents)==SOCKET_ERROR) 
      printError(11); 

     if((wsaEvents.lNetworkEvents & FD_ACCEPT)==FD_ACCEPT) { 
      SOCKET tempSock = accept(s, (struct sockaddr*) &from, &fromLen); 
      s = tempSock; //switch our old socket to the new one 

      char acceptAddr[100]; 
      char* msg = "Connnection from [%s] accepted."; 
      //sprintf(acceptAddr, msg, inet_ntoa(from.sin_addr)); 
      sprintf_s(acceptAddr, strlen(msg) + 100, msg, inet_ntoa(from.sin_addr)); 

      cout << acceptAddr << endl; 
      hasClient = true; 
     } 
     else if((wsaEvents.lNetworkEvents & FD_READ) == FD_READ){ 
      char buffer[1000]; 
      memset(buffer, 0, sizeof(buffer)); 
      recv(s, buffer, sizeof(buffer)-1, 0); 

      receiveAction(string(buffer)); 

      //cout << buffer << endl; 
     } 
     else if((wsaEvents.lNetworkEvents & FD_CLOSE) == FD_CLOSE){ 
      shutdown(s, SD_BOTH); 
      closesocket(s); 
      cout << "socket closed" << endl; 
      startServer(); // start server again 
      return 0; 
     } 
     else if(wsaEvents.lNetworkEvents==0) { 
      printError(14); 
     cout << "lNetworkEvents==0" << endl; 
     } 
    } 
} 

void startServer(){ 
    listenOnPort(port); 
} 

这是PHP代码。

/* Get the port for the WWW service. */ 
// $service_port = getservbyname('www', 'tcp'); 
$service_port = "1111"; 

/* Get the IP address for the target host. */ 
$address = "192.168.3.5"; 

/* Create a TCP/IP socket. */ 
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
if ($socket === false) { 
    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; 
    die(); 
} else { 
    //echo "OK.\n"; 
} 

//echo "Attempting to connect to '$address' on port '$service_port'..."; 
$result = socket_connect($socket, $address, $service_port); 
if ($result === false) { 
    echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n"; 
    die(); 
} else { 
    //echo "OK.\n"; 
} 

$out = ''; 

//echo "Sending HTTP HEAD request..."; 
$result = socket_write($socket, $json, strlen($json)); 

if ($result === false) { 
    echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n"; 
    die(); 
} else { 
    //echo "OK.\n"; 
} 


echo socket_read($socket, 2048); 
// while ($out = socket_read($socket, 2048)) { 
    // echo $out; 
// } 

socket_close($socket); 

回答

0

最后它的工作原理,我对winsock的功能,流程等都不甚了解。这是工作中的一个。关键是让侦听器套接字保持活动状态,然后将客户端/接受的套接字存储在另一个地方。

SOCKET sock[2]; 
SOCKADDR_IN from; 
int fromLen = sizeof(from); 
int port = 1111; 
int listenOnPort(int portNo) 
{ 
    WSAData w; 

    int error = WSAStartup(0x0202, &w); // fill in wsa info 

    if(error) 
    { 
     printError(5); 
     return 0; 
    } 

    if(w.wVersion != 0x0202) 
    { 
     printError(6); 
     WSACleanup(); 
     return 0; 
    } 

    SOCKADDR_IN addr; 
    SOCKET client; 

    addr.sin_family = AF_INET; 
    addr.sin_port = htons(portNo); 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 

    sock[0] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    if(sock[0] == INVALID_SOCKET) 
    { 
     printError(7); 
     return 0; 
    } 

    BOOL bOptVal = TRUE; 
    int bOptLen = sizeof (BOOL); 
    if(setsockopt(sock[0], SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen) == SOCKET_ERROR) 
    { 
     printError(12); 
     return 0; 
    } 

    if(bind(sock[0], (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) 
    { 
     printError(8); 
     return 0; 
    } 

    if(listen(sock[0], 1) == SOCKET_ERROR) //start listening 
    { 
     printError(13); 
     return 0; 
    } 

    //WSAAsyncSelect(sock[0], hwnd, 1045, FD_READ | FD_CONNECT | FD_CLOSE | FD_ACCEPT); 

    cout << "Ready to accept connection, listening on port " << portNo << endl; 

    CreateThread(0,0, &listenForEvents, NULL, 0, 0); 

    //listenForEvents(); 

    return 1; //ok 
} 


DWORD WINAPI listenForEvents(void* lp) 
{ 
    HANDLE sockEv[2]; 
    sockEv[0]=CreateEvent(NULL,TRUE,FALSE,NULL); 
    sockEv[1]=CreateEvent(NULL,TRUE,FALSE,NULL); 
    if(WSAEventSelect(sock[0],sockEv[0],FD_ACCEPT|FD_CONNECT|FD_CLOSE)==SOCKET_ERROR) 
     printError(9); 

    for(;;) { 

     int index = WSAWaitForMultipleEvents(2,sockEv,FALSE,INFINITE,FALSE); 
     //if(index != WSA_WAIT_EVENT_0) 
     // printError(10); 

     index -= WSA_WAIT_EVENT_0; 

     WSANETWORKEVENTS wsaEvents={0}; 
     if(WSAEnumNetworkEvents(sock[index],sockEv[index],&wsaEvents)==SOCKET_ERROR) 
      printError(11); 

     if((wsaEvents.lNetworkEvents & FD_ACCEPT)==FD_ACCEPT) { 
      sock[index+1]= accept(sock[index], (struct sockaddr*) &from, &fromLen); 
      //s = clientSock; //switch our old socket to the new one 

      if(WSAEventSelect(sock[index+1], sockEv[index+1], FD_READ|FD_CLOSE ) == SOCKET_ERROR) 
      { 
       printError(15); 
      } 

      char acceptAddr[100]; 
      char* msg = "Connnection from [%s] accepted."; 
      //sprintf(acceptAddr, msg, inet_ntoa(from.sin_addr)); 
      sprintf_s(acceptAddr, strlen(msg) + 100, msg, inet_ntoa(from.sin_addr)); 

      cout << acceptAddr << endl; 
      hasClient = true; 
     } 
     else if((wsaEvents.lNetworkEvents & FD_READ) == FD_READ){ 
      char buffer[1000]; 
      memset(buffer, 0, sizeof(buffer)); 
      recv(sock[index], buffer, sizeof(buffer)-1, 0); 

      receiveAction(string(buffer)); 

     } 
     else if((wsaEvents.lNetworkEvents & FD_CLOSE) == FD_CLOSE){ 
      shutdown(sock[index], SD_BOTH); 
      closesocket(sock[index]); 
      if(getDebug()) 
      { 
       cout << "socket closed" << endl; 
      } 
      //startServer(); // start server again 
      //return 0; 
     } 
     else if(wsaEvents.lNetworkEvents==0) { 
      printError(14); 
     cout << "lNetworkEvents==0" << endl; 
     } 
    } 
} 
相关问题