Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
309 views
in Technique[技术] by (71.8m points)

c++ - ReleaseSemaphore returns error 6 (Invalid Handle)

I'm trying to use two threads to run a server and a client. I use a semaphore to block the client thread from doing too much before the server has been set up (ListenSocket, etc.).

When The server gets far enough, I use ReleaseSemaphore() but it returns an Invalid Handle error. I've read that there are many possible issues which can be the source of this error.

The exact line is if (ReleaseSemaphore(semaphore, 1, NULL)){} which can be found about 55% of the way into the Server.cpp file

Header.h:

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <process.h>

unsigned int __stdcall servermain(void*);

unsigned int __stdcall clientmain(void*);

static HANDLE semaphore;

Source.cpp:

#include "Header.h"

int main(int argc, char* argv[])
{
    HANDLE serverHandle, clientHandle;

    semaphore = CreateSemaphore(
        NULL,
        0,  //initial count
        1,  //max count
        NULL);

    if (semaphore == NULL){
        printf("CreateSemaphore error: %d
", GetLastError());
        return 1;
    }


    /*call to the methods in the Client and Server files*/
    serverHandle = (HANDLE)_beginthreadex(0, 0, &servermain, 0, 0, 0);
    clientHandle = (HANDLE)_beginthreadex(0, 0, &clientmain, 0, 0, 0);

    WaitForSingleObject(serverHandle, INFINITE);
    WaitForSingleObject(clientHandle, INFINITE);

    CloseHandle(serverHandle);
    CloseHandle(clientHandle);
    CloseHandle(semaphore);

    return 0;
}

Server.cpp:

#include "Header.h"

#pragma comment(lib, "Ws2_32.lib")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

unsigned int __stdcall servermain(void* data)
{
    printf("SERVER STARTED. Thread: %i
", GetCurrentThreadId());

    WSADATA wsaData;
    int iResult;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;

    struct addrinfo
        *result = NULL,
        hints;

    int iSendResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); //initiates the use of the Winsock DLL
    if (iResult != 0) {
        printf("%i Server:	", GetCurrentThreadId());
        printf("WSAStartup failed with error: %d
", iResult);
        return 1;
    }


    //////////////////////////////////////
    // Creating a Socket for the Server //
    //////////////////////////////////////

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the local address and port to be used by the server
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("%i Server:	", GetCurrentThreadId());
        printf("getaddrinfo failed with error: %d
", iResult);
        WSACleanup();
        return 1;
    }


    // Create a SOCKET for the server to listen for client connections
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("%i Server:	", GetCurrentThreadId());
        printf("socket failed with error: %ld
", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }


    //////////////////////
    // Binding a Socket //
    //////////////////////

    // Setup the TCP listening socket
    iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("%i Server:	", GetCurrentThreadId());
        printf("bind failed with error: %d
", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    char answer = 'y'; // char answer[8]; // char *answer = "";
    do{
        printf("%i Server:	", GetCurrentThreadId());

        printf("Would you like to wait for client?(Y/N)	");

        answer = getchar(); // fgets(answer, 1, stdin);
        printf("%c
", answer);
    } while (answer != 'y' && answer != 'n'); // double quotes "" are for c-strings. single quotes '' are for chars.

    if (answer == 'n'){
        return 1;
    }
    else printf("%i Server:	Listening for a client...
", GetCurrentThreadId());

    freeaddrinfo(result);

    printf("Semaphore value: %i
", semaphore);

    //Now that the server is running, signal the semaphore to allow client to connect.
    if (ReleaseSemaphore(semaphore, 1, NULL)) //ReleaseSemaphore() returns a bool value
    {
        printf("%i Server: Semaphore Released
", GetCurrentThreadId());
    }
    else
    {
        printf("Server Release Semaphore error: %d
", GetLastError());
        printf("Server Semaphore value: %i
", semaphore);
        return 1;
    }


    ///////////////////////////
    // Listening on a Socket //
    ///////////////////////////

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("%i Server:	", GetCurrentThreadId());
        printf("Listen failed with error: %ld
", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    ////////////////////////////
    // Accepting a Connection //
    ////////////////////////////

    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("%i Server:	", GetCurrentThreadId());
        printf("accept failed: %d
", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // No longer need server socket
    closesocket(ListenSocket); // This will need to be changed if multiple clients shall be allowed

    //////////////////////////////////////////////
    // Receiving and Sending Data on the Server //
    //////////////////////////////////////////////

    // Receive until the peer shuts down the connection
    do {

        iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0) {
            printf("%i Server:	", GetCurrentThreadId());

            printf("Bytes received: %d
", iResult);

            // Echo the buffer back to the sender
            iSendResult = send(ClientSocket, recvbuf, iResult, 0);
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed: %d
", WSAGetLastError());
                closesocket(ClientSocket); //why close a socket if something doesn't send correctly?
                WSACleanup();
                return 1; //kills main()
            }
            printf("Bytes sent: %d
", iSendResult);
        }
        else if (iResult == 0)
            printf("Connection closing...
");
        else {
            printf("recv failed with error: %d
", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup(); //function terminates use of the Winsock 2 DLL (Ws2_32.dll)
            return 1;
        }

    } while (iResult > 0);

    // shutdown the send half of the connection since no more data will be sent
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("%i Server:	", GetCurrentThreadId());
        printf("shutdown failed with error: %d
", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }

    // cleanup
    closesocket(ClientSocket);
    WSACleanup();

    _endthreadex(0); //end thread within the thread.
    return 0;
}

Client.cpp:

#include "Header.h"

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

unsigned int __stdcall clientmain(void* data)
{
    printf("CLIENT STARTED. Thread: %i
", GetCurrentThreadId());

    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
        *ptr = NULL,
        hints;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;

    // Validate the parameters
    /*if (argc != 2) {
        printf("usage: %s server-name
", argv[0]);
        return 1;
    }*/


    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("%i Client:	", GetCurrentThreadId());
        printf("WSAStartup failed with error: %d
", iResult);
        return 1;
    }

    printf("Client winsock initialized
");

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    /*iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d
", iResult);
        WSACleanup();
        return 1;
    }*/


    printf("%i Client: before semaphore
", GetCurrentThreadId());
    //Wait for Server to be up and running

    bool cont = TRUE;
    while (cont)
    {
        DWORD returnval = WaitForSingleObject(semaphore, 0L); // 0 vs 0L ?

        //printf("Semaphore value: %i
", semaphore);

        switch (returnval)
        {
            // The semaphore object was signaled.
            case WAIT_OBJECT_0:
                printf("Thread %d: wait succeeded
", GetCurrentThreadId());

                break;

                // The semaphore was nonsignaled, so a time-out occurred.
            case WAIT_TIMEOUT:
                printf("Thread %d: wait timed out
", GetCurrentThreadId());
                break;
        }
    }

    printf("%i Client: after semaphore
", GetCurrentThreadId());

    // Attempt to connect to an address until one succeeds
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("%i Client:	", GetCurrentThreadId());
            printf("socket failed with error: %ld
", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("%i Client:	", GetCurrentThreadId());
        printf("Unable to connect to server!
");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        printf("%i Client:	", GetCurrentThreadId());
        printf("send failed with error: %d
", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld
", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You declare semaphore as a static HANDLE in header.h. That means that every source module that includes "header.h" will have its own copy of that variable. Thus, the semaphore in main.cpp that holds the Windows semaphore handle is a different variable than the semaphore referenced in server.cpp.

Remove the static from the declaration in header.h, replace it with extern, and add a definition for it in main.cpp.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...