LNK1169 bei Verwendung von Threadsynchronisation via CRITICAL_SECTION



  • Ich mache ein paar erste Gehversuche mit Threadsynchronisation bei einem Socket-Server. Das Programm ist in drei Dateien aufgeteilt, die main, welche denb Thread startet, basic_server für den Socket-Verkehr und eine Helferdatei ws-util, die nur die Verwendung der winsockets etwas vereinfacht. In basic_server.h wird

    CRITICAL_SECTION Section;
    

    definiert. So kann main() sie initialisieren und basic_server.cpp die kritischen Abschnitte schließen und freigeben. Obwohl alle Header Include-Guards verwenden bekomme ich folgenden Linker-Fehler:

    main.obj : error LNK2005: "struct _RTL_CRITICAL_SECTION Section" (?Section@@3U_RTL_CRITICAL_SECTION@@A) ist bereits in basic-server.obj definiert.
    WinSocket.exe : fatal error LNK1169: Mindestens ein mehrfach definiertes Symbol gefunden.
    

    Ich verstehe einfach nicht, wo eine doppelte Definition stattfinden soll. Falls es wichtig ist, hier der source (ws-util lasse ich weg, es dürfte keine Rolle spielen):

    MAIN

    #include <winsock.h>
    #include <stdlib.h>
    #include <iostream>
    #include <windows.h>
    #include <process.h>
    
    #include "basic-server.h"
    
    using namespace std;
    
    int main(int argc, char* argv[])
    {
    	struct SocketParams params;
    	params.ip	= "127.0.0.1";
    	params.port = 4242;
    
    	cout << "SERVER MAIN STARTED" << endl;
    	cout << "starting thread.." << endl;
    
    	InitializeCriticalSection(&Section);
    
    	HANDLE thread = (HANDLE)_beginthread(startServer, 0, &params);
    
    	//cout << "thread started; handle: "<< thread << endl;
    
    	while(1)
    	{
    		cout << strlen(getExpression()) << endl;
    		Sleep(500);
    	}
    
    	DeleteCriticalSection(&Section);
    
    	getchar();
    
        return 0;
    }
    

    BASIC_SERVER_H

    #ifndef BASIC_SERVER_H
    #define BASIC_SERVER_H
    
    #include <winsock.h>
    
    struct SocketParams
    {
    	int port;
    	char* ip;
    };
    
    CRITICAL_SECTION Section;
    
    SOCKET setUpListener(const char* pcAddress, int nPort);
    SOCKET acceptConnection(SOCKET ListeningSocket, sockaddr_in& sinRemote);
    char* getExpression();
    bool echoIncomingPackets(SOCKET sd);
    int doWinsock(const char* pcHost, int nPort);
    void startServer(void* arg);
    int getSome();
    
    #endif
    

    BASIC_SERVER_CPP

    #include <winsock.h>
    #include <iostream>
    #include "ws-util.h"
    #include "basic-server.h"
    
    using namespace std;
    
    const int kBufferSize = 1024;
    
    char receivedString[1024];
    
    int getSome()
    {
    	return 55;
    }
    
    char* getExpression()
    {
    	//EnterCriticalSection(&Section);
    	return receivedString;
    	//LeaveCriticalSection(&Section);
    }
    
    void startServer(void* args)
    {
    	struct SocketParams* params = (struct SocketParams*) args;
    	WSAData wsaData;
    	int nCode;
    
    	// Start Winsock up
    	if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0)
    	{
    		cerr << "WSAStartup() returned error code " << nCode << "." << endl;
    	    //return 255;
    	}
    
    	// Call the main example routine.
    	doWinsock("127.0.0.1", 4242);
    
    	// Shut Winsock back down and take off.
        WSACleanup();
    }
    
    //// DoWinsock /////////////////////////////////////////////////////////
    // The module's driver function -- we just call other functions and
    // interpret their results.
    
    int doWinsock(const char* pcAddress, int nPort)
    {
        // Begin listening for connections
        cout << "Establishing the listener..." << endl;
    
    	SOCKET ListeningSocket = setUpListener(pcAddress, htons(nPort));
        if (ListeningSocket == INVALID_SOCKET)
        {
    		cout << "INVALID SOCKET";
            cout << endl << WSAGetLastErrorMessage("establish listener") << endl;
            return 3;
        }
    
        // Spin forever handling clients
        while (1)
        {
            // Wait for a connection, and accepting it when one arrives.
            cout << "Waiting for a connection..." << flush;
            sockaddr_in sinRemote;
            SOCKET sd = acceptConnection(ListeningSocket, sinRemote);
            if (sd != INVALID_SOCKET)
            {
                cout << "Accepted connection from " <<
                        inet_ntoa(sinRemote.sin_addr) << ":" <<
                        ntohs(sinRemote.sin_port) << "." << endl;
            }
            else
            {
                cout << endl << WSAGetLastErrorMessage("accept connection") << endl;
                return 3;
            }
    
            // Bounce packets from the client back to it.
            if (echoIncomingPackets(sd))
            {
                // Successfully bounced all connections back to client, so
                // close the connection down gracefully.
                cout << "Shutting connection down..." << flush;
                if (ShutdownConnection(sd))
                {
                    cout << "Connection is down." << endl;
                }
                else
                {
                    cout << endl << WSAGetLastErrorMessage(
                            "shutdown connection") << endl;
                    return 3;
                }
            }
            else
            {
                cout << endl << WSAGetLastErrorMessage(
                        "echo incoming packets") << endl;
                return 3;
            }
        }
    
    #if defined(_MSC_VER)
        return 0;       // warning eater
    #endif
    }
    
    //// SetUpListener /////////////////////////////////////////////////////
    // Sets up a listener on the given interface and port, returning the
    // listening socket if successful; if not, returns INVALID_SOCKET.
    
    SOCKET setUpListener(const char* pcAddress, int nPort)
    {
        u_long nInterfaceAddr = inet_addr(pcAddress);
        if (nInterfaceAddr != INADDR_NONE)
        {
            SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);
    
            if (sd != INVALID_SOCKET)
            {
                sockaddr_in sinInterface;
                sinInterface.sin_family = AF_INET;
                sinInterface.sin_addr.s_addr = nInterfaceAddr;
                sinInterface.sin_port = nPort;
                if (bind(sd, (sockaddr*)&sinInterface, sizeof(sockaddr_in)) != SOCKET_ERROR)
                {
                    listen(sd, 1);
                    return sd;
                }
                else cout << "SOCKET_ERROR";
            }
            else cout << "INVALID_SOCKET";
        }
        else cout << "INADDR_NONE";
    
        return INVALID_SOCKET;
    }
    
    //// AcceptConnection //////////////////////////////////////////////////
    // Waits for a connection on the given socket.  When one comes in, we
    // return a socket for it.  If an error occurs, we return
    // INVALID_SOCKET.
    
    SOCKET acceptConnection(SOCKET ListeningSocket, sockaddr_in& sinRemote)
    {
        int nAddrSize = sizeof(sinRemote);
        return accept(ListeningSocket, (sockaddr*)&sinRemote, &nAddrSize);
    }
    
    //// EchoIncomingPackets ///////////////////////////////////////////////
    // Bounces any incoming packets back to the client.  We return false
    // on errors, or true if the client closed the socket normally.
    
    bool echoIncomingPackets(SOCKET sd)
    {
        // Read data from client
        char acReadBuffer[kBufferSize];
        int numReadBytes;
    
        do 
    	{
    		EnterCriticalSection(&Section);
    
            numReadBytes = recv(sd, acReadBuffer, kBufferSize, 0);
    
    		if (numReadBytes > 0) 
    		{
                cout << "Received " << numReadBytes <<
                        " bytes from client." << endl;
    
    			acReadBuffer[numReadBytes] = '\0';
    
    			strcpy(receivedString, acReadBuffer);
    
    			cout << "acReadBuffer  : " << acReadBuffer << endl;
    			cout << "receivedString: " << receivedString << endl << endl;
    
            }
            else if (numReadBytes == SOCKET_ERROR) 
    		{
                return false;
            }
    
    		LeaveCriticalSection(&Section);
    
        } while (numReadBytes != 0);
    
        cout << "Connection closed by peer." << endl;
        return true;
    }
    

    Schon einmal vielen Dank für alle, die sich die Mühe machen, das durchzusehen!



  • Serethos schrieb:

    Obwohl alle Header Include-Guards verwenden bekomme ich folgenden Linker-Fehler:

    <Gebetsmühle>
    Include-Guards schützen dich nur vor dem mehrfachen Einbinden einer Headerdatei in eine Übersetzungseinheit.
    </Gebetsmühle>

    Deine Variable Section landet dadurch, dass sie in der Headerdatei definiert ist, in mehr als einer Übersetzungseinheit. Daher weiß der Linker nicht, welche er benutzen soll. Und das ist der Grund dafür, dass man normalerweise keine Variablen in Headerdateien definiert.

    Deklarier die Variable als extern in der Headerdatei, und definiere sie in einer cpp-Datei.



  • Danke für die Hilfe!


Anmelden zum Antworten