LNK2019: 未解析的外部符号

4
我看到了很多类似的问题,但是在它们的帮助下我仍然无法解决这个问题。我知道这是一个链接问题,但是从我所看到的情况来看,我的链接已经处理好了。
我正在编写一个聊天服务器/客户端(参考这篇文章)。
我定义了一个类来保存服务器函数,并有一个头文件来处理所有的包含文件。
以下是头文件内容:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include "resource1.h"


class ChatServer
{
    public: int InitServer(HINSTANCE hInst);

    public: void ReportError(int errorCode, const char *whichFunc);
};

这是实际的服务器“类”:
#include "server.h"
#define NETWORK_ERROR -1
#define NETWORK_OK     0
//Keeps stuff for the server    
int ChatServer::InitServer(HINSTANCE hInst)
    {
        WORD sockVersion;
        WSADATA wsaData;
        int nret;

        sockVersion = MAKEWORD(1,1); //Version 1.1

        //Init winsock
        WSAStartup(sockVersion, &wsaData);

        //Create listening socket
        SOCKET listeningSocket;

        //AFINET - Go over TCP
        //SOCK_STREAM - Stream oriented socket
        //IPPROTO_TCP - Use tcp rather than udp
        listeningSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);

        if(listeningSocket == INVALID_SOCKET)
        {
            nret = WSAGetLastError(); //Get error detail
            ReportError(nret, "socket()");

            WSACleanup();

            return NETWORK_ERROR;
        }

        SOCKADDR_IN serverInfo;

        serverInfo.sin_family = AF_INET;
        serverInfo.sin_addr.s_addr = INADDR_ANY;
        serverInfo.sin_port = htons(1337); 

        //Bind the socket to local server address.
        nret = bind(listeningSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));

        if(nret == SOCKET_ERROR)
        {
            nret = WSAGetLastError();
            ReportError(nret, "bind()");
            WSACleanup();
            return NETWORK_ERROR;
        }

        //Make socket listen
        nret = listen(listeningSocket, 10); //Up to 10 connections at the same time.

        if(nret = SOCKET_ERROR)
        {
            nret = WSAGetLastError();
            ReportError(nret, "listen()");
            WSACleanup();
            return NETWORK_ERROR;
        }

        //Wait for client
        SOCKET theClient;
        theClient = accept(listeningSocket, NULL, NULL);

        if(theClient == INVALID_SOCKET)
        {
            nret = WSAGetLastError();
            ReportError(nret, "accept()");
            WSACleanup();
            return NETWORK_ERROR;
        }

        //Send and receive from the client, and finally,
        closesocket(theClient);
        closesocket(listeningSocket);

        //shutdown
        WSACleanup();
        return NETWORK_OK;
    }



void ChatServer::ReportError(int errorCode, const char *whichFunc)

    {

       char errorMsg[92];                   // Declare a buffer to hold
                                            // the generated error message
       ZeroMemory(errorMsg, 92);            // Automatically NULL-terminate the string
       // The following line copies the phrase, whichFunc string, and integer errorCode into the buffer
       sprintf(errorMsg, "Call to %s returned error %d!", (char *)whichFunc, errorCode);



       MessageBox(NULL, errorMsg, "socketIndication", MB_OK);

    }

最后,程序的入口main.cpp文件调用“ChatServer::InitServer(g_hInst)”。该文件相当大,所以我省略了它,但如果需要,我也可以发布它。
我收到的错误消息类似于下面这个,但它们都指出与winsockets API相关的api函数的问题:
Error   3   error LNK2019: unresolved external symbol _closesocket@4 referenced in function "public: int __thiscall ChatServer::InitServer(struct HINSTANCE__ *)" (?InitServer@ChatServer@@QAEHPAUHINSTANCE__@@@Z)  

如我之前所述,我相信这个问题与编译器对于应该链接到winsock.h的“closesocket”等函数的误解有关。

非常感谢您的任何建议,也感谢您阅读所有这些无意义的文字:)


1
你为什么不使用winsock2.h? - Drahakar
5
你是否链接了wininet.lib和ws2_32.lib库? - stijn
你不需要在每个成员函数声明前面加上 public。一旦您列出访问限定符,随后的所有内容都将具有相同的访问权限,直到您列出不同的访问限定符。 - Praetorian
1
实际上,这是Drahakar和stinj上面所说的结合体。将#include<winsock2.h>作为第一个要包含的头文件(在winsock2.h已经包含的Windows.h之前)。然后从项目设置中添加ws2_32.lib到您的链接库中。Praetorian关于“public”也是正确的。 - selbie
@selbie;你应该这样回答,我按照你说的做了,错误消失了。谢谢。 - Phil
@Phil - 这样做会太容易了(而且对其他两个人提出的建议不公平)。 - selbie
3个回答

10
这些链接错误总是一样的:你正在使用链接器找不到的符号。你需要告诉链接器链接包含这些符号的库。
正如我之前所说,我认为这个问题与编译器误解如何处理像“closesocket”这样应该链接到winsock.h的函数有关。
不,closesocket没有链接到winsock.h。winsock.h是一个头文件,不是一个库。它可以包含对closesocket的声明,这对编译器来说没问题,但链接器真的需要知道那个函数的代码在哪里,这样它才能将你的程序链接到它上面。
虽然如此,你应该使用winsock2.h而不是winsock.h。Windows套接字API 2.0始于1994年,版本1已经过时了。
你可以在此函数文档的底部看到它所在的库是ws2_32.lib。

2
你可以这样定义你的类:
class ChatServer
{
public:
    int InitServer(HINSTANCE hInst);
    void ReportError(int errorCode, const char *whichFunc);
};

然而,您的错误是由于未包含输入库引起的。在您的项目输入行中添加 winsock 库的依赖项,还要考虑使用 winsock2.h。
供参考:http://msdn.microsoft.com/en-us/library/ms737629(v=vs.85).aspx

2
仅仅包含.h文件并不会导致实现函数的代码被链接。 .h文件告诉编译器这些函数存在于某个地方,以及它们的签名是什么。你仍然需要使包含函数实现的库对链接器可用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接