CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 2 of 2
  1. #1
    Join Date
    Apr 2007
    Posts
    90

    Server socket can connect few times only (Winsock C++)

    Hi I am trying to write a server winsock in C++ to allow connection from PHP client code. The PHP will request the data from server, receive then close the connection. However, after 2-3 times of connection, when the PHP request again, it hang at the socket_read(), the page keep loading, and the server does not receive the FD_ACCEPT event. Is it because of TIME_WAIT that the connection is not yet closed ? Any suggestion on code improvement will be nice too.

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

    --------------------------------------------------------------------------------------
    This is the PHP code.

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

  2. #2
    Join Date
    Apr 2007
    Posts
    90

    Re: Server socket can connect few times only (Winsock C++)

    Finally it works, I wasn't quite understand on the winsock functions, flow, etc. This is the working one. The key is to let the listener socket keep alive, then store the client/accepted socket in another place.


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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured