【问题标题】:Server socket can connect few times only (Winsock C++)服务器套接字只能连接几次(Winsock C++)
【发布时间】:2013-03-13 03:07:53
【问题描述】:

您好,我正在尝试用 C++ 编写服务器 winsock 以允许从 PHP 客户端代码进行连接。 PHP将从服务器请求数据,接收然后关闭连接。但是,2-3次连接后,再次请求PHP时,在socket_read()处挂起,页面一直在加载,服务器没有收到FD_ACCEPT事件。是因为 TIME_WAIT 连接还没有关闭吗?任何关于代码改进的建议也会很好。

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);

【问题讨论】:

    标签: php c++ windows sockets winsock


    【解决方案1】:

    终于成功了,我对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;
          }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-02
      • 2018-11-29
      • 1970-01-01
      相关资源
      最近更新 更多