C++ 链接器错误 LNK2001 和 LNK1120 Winsock2 Lib

C++ Linker error LNK2001 and LNK1120 Winsock2 Lib

我似乎无法摆脱这个编译器错误。

Error   1   error LNK2001: unresolved external symbol "public: __thiscall Socket::Socket(void)" (??0Socket@@QAE@XZ) C:\arma-to-socket\ConsoleApplication5\ConsoleApplication5\ConsoleApplication5.obj   ConsoleApplication5
Error   2   error LNK1120: 1 unresolved externals   C:\arma-to-socket\ConsoleApplication5\Release\ConsoleApplication5.exe   ConsoleApplication5

据我所知,我已经链接了正确的 lib 文件:

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

并包括我认为我需要的一切:

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string> 

完整的源代码:

Console app to debug(稍后在另一个项目中编译为dll): 主 cpp 文件

// ConsoleApplication5.cpp : Defines the entry point for the console application.
//

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

#include "stdafx.h"
#include <iostream>
#include "Socket.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{       
     char myIP[10] = "127.0.0.1";
     Socket mySocket;
     mySocket.Init(*myIP);
     mySocket.Connect();
     mySocket.Send("hello world");

     return 0;
}

Socket.h

#pragma once

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string> 

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

#define DEFAULT_BUFLEN 1024
#define DEFAULT_PORT "9999"
using namespace std;
class Socket
{
public:
     Socket();
     Socket(CHAR);
     void Init(CHAR);
     int Connect();
     int Send(string input);
     string Recieve();
     int Disconnect();
     string SendRecieve(string input);
     int getStatus();
     char getStatusMsg();
     ~Socket();
private:
     struct addrinfo *result = NULL,
         *ptr = NULL,
         hints;
     char *sendbuf = "this is a test";
     char recvbuf[DEFAULT_BUFLEN];
     int iResult;
     int recvbuflen = DEFAULT_BUFLEN;
     int status;
     CHAR statusMsg;
     SOCKET ConnectSocket;
     CHAR addressChar;
     CHAR *addressPtr;
     WSADATA wsaData;
};

Socket.cpp:

#include "stdafx.h"
#include <string> 
#include "Socket.h"

Socket::Socket(CHAR address){
    Init(address);

}



void Socket::Init(CHAR address)
{
    addressChar = address;
    addressPtr = &addressChar;

    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
        *ptr = NULL,
        hints;
    char *sendbuf = "this is a test";
    iResult = getaddrinfo(addressPtr, DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        statusMsg = ("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        status = 1;
    }

    // Attempt to connect to the first address returned by
    // the call to getaddrinfo
    ptr = result;

    // Create a SOCKET for connecting to server
    ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
        ptr->ai_protocol);
    if (ConnectSocket == INVALID_SOCKET) {
        statusMsg = ("Error at socket(): %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        status = 1;
    }
    status = -1;
}

int Socket::Connect() {
    iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        closesocket(ConnectSocket);
        ConnectSocket = INVALID_SOCKET;
    }
    // Should really try the next address returned by getaddrinfo
    // if the connect call failed
    // But for this simple example we just free the resources
    // returned by getaddrinfo and print an error message

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        //statusMsg = "Unable to connect to server!";
        WSACleanup();
        status = 1;
    }
    if (status = 1){
        return 1;
    }
    else {
        return 0;
    }

};

int Socket::Send(string input){
    char *sendbuf = (char*)input.c_str();
    // Send an initial buffer
    iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        statusMsg = ("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        status = 1;
    }

    statusMsg = ("Bytes Sent: %ld\n", iResult);

    // shutdown the connection for sending since no more data will be sent
    // the client can still use the ConnectSocket for receiving data
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        statusMsg = ("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        status = 1;
    }
    if (status = 1){
        return 1;
    }
    else {
        return 0;
    }
};

string Socket::Recieve() {
    string rtn = "";
    // Receive data until the server closes the connection
    do {
        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0){
            string rtn = recvbuf;
        }
        //else if (iResult == 0)
        //statusMsg = ("Connection closed\n");
        else{
            statusMsg = ("recv failed: %d\n", WSAGetLastError());

        }
    } while (iResult > 0);
    return rtn;

};

int Socket::Disconnect(){
    // shutdown the send half of the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        //printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        status = 1;
    }
    return 0;

};

string Socket::SendRecieve(string input){
    Send(input);
    return Recieve();

};

int Socket::getStatus(){

    return status;
}
char Socket::getStatusMsg(){
    return statusMsg;
}
Socket::~Socket()
{
    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    status = 0;
};

注意:在预期的目标项目中编译为 dll 时,它编译没有错误,但在运行时崩溃。

目标项目的主文件:

// threaded_example.cpp : Defines the exported functions for the DLL application. 
// original threading arma plugin from http://killzonekid.com
//

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h" 
#include <string> 
#include <unordered_map> 
#include <thread> 
#include <mutex> 
#include <atomic> 
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


#include "Socket.h"


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 1024
#define DEFAULT_PORT "9999"


//todo: pass parameters

//todo multi part returns




// source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737591%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

using namespace std;

//string socketClient(string input);

char address[] = "127.0.0.1";


Socket mySocket( *address);

struct Data
{
    bool ready = false;
    string params = "";
    string result = "";
};

unordered_map<long int, Data> tickets;
mutex mtx;
atomic<bool> worker_working(false);
long int id = 0;// global ticket id 
long int cur_id = 0; // current ticket id 


extern "C"
{
    __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function);
}

void worker()
{
    while (worker_working = id > cur_id) // next ticket exists? 
    {
        string output;
        mtx.lock();
        Data ticket = tickets[++cur_id];// copy ticket 
        mtx.unlock();

        string input = ticket.params; // get input 
        //string output = "output: " + input; // process input 
        //Sleep(10); //sleep for 0.01 sec (FOR TESTING PURPOSES ONLY) 
        switch (mySocket.getStatus()){

        case -1:
            mySocket.Connect();


        case 0:
            output = mySocket.SendRecieve(input);
            break;

        case 1:
            output = mySocket.getStatusMsg();
                if (output == ""){
                    output = "an uknown eror occured";
                }
            break;


        };
        //string output = socketClient(input);
        //code here
        //output = output +"\n"+ "[=16=]";

        ticket.result = output; // prepare result 
        ticket.ready = true; // notify about result 
        mtx.lock(); tickets[cur_id] = ticket; // copy back the result 
        mtx.unlock();
    }
}


void __stdcall RVExtension(char *output, int outputSize, const char *function)
{
    if (!strncmp(function, "r:", 2)) // detect checking for result 
    {
        long int num = atol(&function[2]); // ticket number or 0
        if (tickets.find(num) != tickets.end()) // ticket exists 
        {
            mtx.lock();
            if (tickets[num].ready) // result is ready 
            {
                strncpy_s(output, outputSize, tickets[num].result.c_str(), _TRUNCATE); // result 
                tickets.erase(num); // get rid of the read ticket 
                mtx.unlock();
                return;
            }
            mtx.unlock();
            strncpy_s(output, outputSize, "WAIT", _TRUNCATE);// result is not ready 
            return;
        }
        strncpy_s(output, outputSize, "EMPTY", _TRUNCATE); // no such ticket 
    }
    else if (!strncmp(function, "s:", 2)) // detect ticket submission 
    {
        Data data;
        data.params = string(&function[2]); // extract params 
        mtx.lock(); tickets.insert(pair<long int, Data>(++id, data)); // add ticket to the queue 
        mtx.unlock();
        if (!worker_working) // if worker thread is finished, start another one 
        {
            worker_working = true;
            thread worker(worker);
            worker.detach(); // start parallel process 
        }
        strncpy_s(output, outputSize, to_string(id).c_str(), _TRUNCATE); // ticket number 
    }
    else
    {
        strncpy_s(output, outputSize, "INVALID COMMAND", _TRUNCATE); // other input 
    }
}

我的经验主要是python和PHP。这是我第一个使用 C++ 和 VS2013 的正确项目。

我认为您只是缺少函数 Socket() 的实现。在您的 .cpp 中实施 Socket(),一切都应该有效。

该错误不是编译器错误,而是链接器错误。两者之间是有区别的,知道了区别会让你更清楚手头的问题。

链接器错误表明它找不到实现的 Socket::Socket(void) 函数。查看您的代码,这似乎缺少 Socket 的无参数(默认)构造函数的实现。

你的代码编译没有问题,因为编译器不关心你调用的函数是否真的存在。只要有函数的声明(就像您在代码中所做的那样),或者函数体位于函数调用之前,编译器就会说 "ok, no problem".

编译成功后,链接器现在实际上会尝试查找您的代码正在调用的函数。如果它在其他目标模块或库中找不到该函数,则链接器会给您 "unresolved external" 错误。如果您收到这些错误,请仔细阅读错误消息,因为错误说明正在调用但无法找到的函数。

链接器看起来像疯了似的乱七八糟的东西——这只是名称修改,而不是对此类错误的关注。消息的重要部分是 class 和函数名称,以及参数(在本例中为 void,表示没有参数)。