C ++服务器 - 客户端FTP模拟

时间:2012-10-26 12:25:09

标签: c++ ftp client-server simulation

我在服务器 - 客户端FTP模拟程序方面遇到了一些问题。该程序不断给我“未定义的引用”错误。我在Windows上使用C :: B 10.05,尝试包括winsock.h,winsock2.h,以及我在互联网上找到的更多解决方案,但它没有用。这是源代码。 任何帮助都是非常有用的。 感谢。

//Router Head file
#include <winsock.h>
#include <fstream>
#include <iostream>
#include <time.h>
#include <winsock2.h>
#include <list>
#include <stdio.h>

#define MAXBUFSIZE 2048             //maximum packet size
#define MAXHOSTNAMELEN 256          //maximum length of host name
#define ROUTER_PORT1 7000           //router port number 1
#define ROUTER_PORT2 7001           //router port number 2
#define PEER_PORT1 5000             //port number of peer host 1
#define PEER_PORT2 5001             //port number of peer host 2
#define TIMEOUT_USEC 300000         //time-out value
#define TRACE 1
using namespace std ;

struct EVENT_LIST
{
    bool empty;
    DWORD count;                    //count is the packet number
    short destination;              //destination of this packet
    int len;                        //length of this packet
    char Buffer[MAXBUFSIZE];        //buffer for packet
};

class Router
{
public:
    char localhost[MAXHOSTNAMELEN];     //local host name
    Router(char *fn="log.txt");
    ~Router();
    void Run();
private:
    ofstream fout;
    float damage_rate, delay_rate;              //damage rate: dropped and delayed
    SOCKET Sock1, Sock2;            //sockets used for communcation with peer host 1 and 2
    EVENT_LIST FileBuf;     //buffer for delayed packets
protected:
    SOCKADDR_IN sa_in_peer1;        // address structure for peer host 1 address
    SOCKADDR_IN sa_in_peer2;        // address structure for peer host 2 address
    bool IsDamage() const;
    bool IsDelayed() const;
    void SendProc();
};

//Router.cpp
//////////////////////////////////////////////////////////
//
//  Router Constructor
//  arguements:
//      fn: A string of log file name
//
//////////////////////////////////////////////////////////

Router::Router(char *fn)        //Constructor
{
    WSADATA wsadata;
    HOSTENT* hp;
    char peer_name1[MAXHOSTNAMELEN], peer_name2[MAXHOSTNAMELEN];
    SOCKADDR_IN sa_in;

    FileBuf.empty=true;

    try
    {
        if (WSAStartup(0x0202,&wsadata)!=0)
            throw "Error in starting WSAStartup()\n";
    }

    //Display any needed error response.
    catch (char *str) { cerr<<str<<":"<<dec<<WSAGetLastError()<<endl; return;}

    //Get Host name
    gethostname(localhost,MAXHOSTNAMELEN);
    cout<<"Router starting on host:"<<localhost<<endl<<flush;

    //Open the log file
    fout.open(fn);

    try
    {
        //Create the Udp Sock1
        if((Sock1 = socket(AF_INET,SOCK_DGRAM,0))==INVALID_SOCKET)
            throw "Create UDP Socket1 failed\n";

        //Fill-in UDP Port and Address info.
        sa_in.sin_family = AF_INET;
        sa_in.sin_port = htons(ROUTER_PORT1);
        sa_in.sin_addr.s_addr = htonl(INADDR_ANY);

        //Bind the UDP port1
        if (bind(Sock1,(LPSOCKADDR)&sa_in,sizeof(sa_in)) == SOCKET_ERROR)
            throw "can't bind the socket1";

        //Create the Udp Sock2
        if((Sock2 = socket(AF_INET,SOCK_DGRAM,0))==INVALID_SOCKET)
            throw "Create UDP Socket2 failed\n";

        //Fill-in UDP Port and Address info.
        sa_in.sin_family = AF_INET;
        sa_in.sin_port = htons(ROUTER_PORT2);
        sa_in.sin_addr.s_addr = htonl(INADDR_ANY);

        //Bind the UDP port2
        if (bind(Sock2,(LPSOCKADDR)&sa_in,sizeof(sa_in)) == SOCKET_ERROR)
            throw "can't bind the socket2";

        cout<<"\nPlease enter the first peer host name:"<<flush;        //enter the dropping rate.
        cin>>peer_name1;
        cout<<"\nPlease enter the second peer host name:"<<flush;       //enter the dropping rate.
        cin>>peer_name2;
        cout<<"\nPlease enter the drop rate:"<<flush;       //enter the dropping rate.
        cin>>damage_rate;
        cout<<"\nPlease enter the delay rate:"<<flush;      //enter the dropping rate.
        cin>>delay_rate;

        //creat peer host1
        if((hp=gethostbyname(peer_name1)) == NULL)
            throw "get server name failed\n";
        memset(&sa_in_peer1,0,sizeof(sa_in_peer1));
        memcpy(&sa_in_peer1.sin_addr,hp->h_addr,hp->h_length);
        sa_in_peer1.sin_family = hp->h_addrtype;
        sa_in_peer1.sin_port = htons(PEER_PORT1);

        //creat peer host2
        if((hp=gethostbyname(peer_name2)) == NULL)
            throw "get client name failed\n";
        memset(&sa_in_peer2,0,sizeof(sa_in_peer2));
        memcpy(&sa_in_peer2.sin_addr,hp->h_addr,hp->h_length);
        sa_in_peer2.sin_family = hp->h_addrtype;
        sa_in_peer2.sin_port = htons(PEER_PORT2);

        if (TRACE)
        {
            fout<<"Peer host 1: "<<peer_name1<<endl;
            fout<<"Peer host 2: "<<peer_name2<<endl;
            fout<<"Damage Rate: "<<damage_rate<<endl;
        }
    }
    catch (char *str) {cerr<<str<<":"<<dec<<WSAGetLastError()<<endl; exit(1);}

    srand( (unsigned)time( NULL ) );
};

//////////////////////////////////////////////////////////
//
//  Router::IsDamage
//      The function that generates random damages according to damage rate.
//
//////////////////////////////////////////////////////////

bool Router::IsDamage() const
{
    return ( (((float)rand())/RAND_MAX) < ((float)damage_rate/100));
}

//////////////////////////////////////////////////////////
//
//  Router::IsDelayed
//      The function that generates random delayed according to delay rate.
//
//////////////////////////////////////////////////////////

bool Router::IsDelayed() const
{
    return ( (((float)rand())/RAND_MAX) < ((float)delay_rate/100));
};

//////////////////////////////////////////////////////////
//
//  Router::Run
//      The function receives packets from peer hosts and forwards to destinations.
//      It also drops packets and stores delayed packets for future sending.
//      It calls SendProc to send delayed packets.
//
//////////////////////////////////////////////////////////

void Router::Run()
{
    fd_set readfds;
    struct timeval *tp=new timeval;
    SOCKADDR from;
    int RetVal, fromlen, recvlen, wait_count;
    EVENT_LIST temp;
    DWORD CurrentTime, count1, count2;

    count1=0;
    count2=0;
    wait_count=0;
    tp->tv_sec=0;
    tp->tv_usec=TIMEOUT_USEC;

    while (1)
    {
        try
        {
            FD_ZERO(&readfds);
            FD_SET(Sock1,&readfds);
            FD_SET(Sock2,&readfds);
            fromlen=sizeof(from);
            if((RetVal=select(1,&readfds,NULL,NULL,tp))==SOCKET_ERROR)  //check for incoming packets.
                throw "Timer error!";
            else if(RetVal>0)   //There are incoming packets.
            {
                if(!FileBuf.empty) wait_count++;
                if(FD_ISSET(Sock1, &readfds))   //incoming packet from peer host 1
                {
                    if((recvlen=recvfrom(Sock1, temp.Buffer, sizeof(temp.Buffer), 0, &from, &fromlen))==SOCKET_ERROR)
                        throw " Get buffer error!";
                    if (TRACE)
                    {
                        fout<<"Router: Receive packet "<<count1<<" from peer host 1"<<endl;
                        cout<<"Router: Receive packet "<<count1<<" from peer host 1"<<endl;
                    }
                    temp.count=count1;
                    count1++;
                    temp.destination=2;
                }
                else if(FD_ISSET(Sock2, &readfds))  //incoming packet from peer host 2
                {
                    if((recvlen=recvfrom(Sock2, temp.Buffer, sizeof(temp.Buffer), 0, &from, &fromlen))==SOCKET_ERROR)
                        throw " Get buffer error!";
                    if (TRACE)
                    {
                        fout<<"Router: Receive packet "<<count2<<" from peer host 2"<<endl;
                        cout<<"Router: Receive packet "<<count2<<" from peer host 2"<<endl;
                    }
                    temp.count=count2;
                    count2++;
                    temp.destination=1;
                }
                else continue;
                temp.len=recvlen;
                CurrentTime=GetTickCount();
                if(FileBuf.empty&&IsDelayed())      //if the packet is delayed.
                {
                    FileBuf=temp;
                    FileBuf.empty=false;
                    if (TRACE)
                    {
                        fout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been delayed!"<<endl;
                        cout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been delayed!"<<endl;
                    }
                }
                else if(IsDamage()) //if the packet is dropped: dropping packet by no forwarding the packet.
                {
                    if (TRACE)
                    {
                        fout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been dropped by router!"<<endl;
                        cout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been dropped by router!"<<endl;
                    }
                }
                else        //otherwise, packet is forwarded to destination
                {
                    if(temp.destination==1) //forward packets received from 2 to 1.
                    {
                        if(sendto(Sock1, temp.Buffer, temp.len,0,(SOCKADDR*)&sa_in_peer1,sizeof(sa_in_peer1))==SOCKET_ERROR)
                            throw "Send packet error!";
                        if (TRACE)
                        {
                            fout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
                            cout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
                        }
                        if(!FileBuf.empty&&FileBuf.destination==1)
                        {
                            wait_count=0;
                            SendProc();
                        }
                    }
                    else
                    {   //forward packets received from 1 to 2.
                        if(sendto(Sock2, temp.Buffer, temp.len,0,(SOCKADDR*)&sa_in_peer2,sizeof(sa_in_peer2))==SOCKET_ERROR)
                            throw "Send packet error1";
                        if (TRACE)
                        {
                            fout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
                            cout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
                        }
                        if(!FileBuf.empty&&FileBuf.destination==2)
                        {
                            wait_count=0;
                            SendProc();
                        }
                    }
                }
            }
            else //If there is no incoming packet and there is a delayed packets storing in buffer for 3 cycle times (about 0.9 second), call SendProc to send delayed packet.
            {
                if(!FileBuf.empty)
                {
                    wait_count++;
                    if(wait_count>=3)
                    {
                        SendProc();
                        wait_count=0;
                    }
                }
            }
        } //end of try
        catch(char *str) {cerr<<str<<":"<<dec<<WSAGetLastError()<<endl;}
    }//end of while
};

//////////////////////////////////////////////////////////
//
//  Router::SendProc
//      Send delayed packets to the destinations.
//
//////////////////////////////////////////////////////////

void Router::SendProc()
{
    try
    {
        if(FileBuf.destination==1)
        {
            if(sendto(Sock1, FileBuf.Buffer, FileBuf.len,0,(SOCKADDR*)&sa_in_peer1,sizeof(sa_in_peer1))==SOCKET_ERROR)
                throw "Send packet error!";
        }
        else
        {
            if(sendto(Sock2, FileBuf.Buffer, FileBuf.len,0,(SOCKADDR*)&sa_in_peer2,sizeof(sa_in_peer2))==SOCKET_ERROR)
                throw "Send packet error!";
        }
        if (TRACE)
        {
            fout<<"Router: Send delayed packet "<<FileBuf.count<<" received from peer host "<<(FileBuf.destination==1?2:1)<<" to host "<<FileBuf.destination<<endl;
            cout<<"Router: Send delayed packet "<<FileBuf.count<<" received from peer host "<<(FileBuf.destination==1?2:1)<<" to host "<<FileBuf.destination<<endl;
        }
    }
    catch(char *str){cerr<<str<<":"<<dec<<WSAGetLastError()<<endl;}
    FileBuf.empty=true;
};

//////////////////////////////////////////////////////////
//
//  Router Destructor
//  arguements:
//      fn: A string of log file name
//
//////////////////////////////////////////////////////////

Router :: ~Router()
{
    closesocket(Sock1);
    closesocket(Sock2);

    /* When done, uninstall winsock.dll (WSACleanup()) and exit */
    WSACleanup();

    //close log file
    fout.close();
};

//////////////////////////////////////////////////////////
//
//  Main function
//
//////////////////////////////////////////////////////////

int main()
{
    Router router;
    router.Run();
  return 0;
}

1 个答案:

答案 0 :(得分:0)

“未定义参考”错误是链接器错误。链接器错误无法通过包含其他头文件来解决。从概念上讲,头文件包含函数的声明(函数的名称,其参数的类型,其返回值的类型)。您包括头文件,以便您可以引用程序头中声明的函数。在链接期间,这些引用被解析为指向包含这些功能的实际实现的库。

当您收到“未定义的引用”错误时,这意味着链接器无法在被告知要链接的库中找到您在代码中引用的函数的实现。为了解决这个问题,您必须找到实现缺少功能的库,并告诉编译器针对该库进行链接。

编译程序时,出现以下错误:

error LNK2019: unresolved external symbol "___WSAFDIsSet@8" referenced in function ""public: void __thiscall Router::Run(void)" (?Run@Router@@QAEXXZ)".
error LNK2019: unresolved external symbol "__imp__bind@12" referenced in function "__catch$??0Router@@QAE@PBD@Z$0".
error LNK2019: unresolved external symbol "__imp__closesocket@4" referenced in function ""public: __thiscall Router::~Router(void)" (??1Router@@QAE@XZ)".
error LNK2019: unresolved external symbol "__imp__htonl@4" referenced in function "__catch$??0Router@@QAE@PBD@Z$0".
error LNK2019: unresolved external symbol "__imp__htons@4" referenced in function "__catch$??0Router@@QAE@PBD@Z$0".
error LNK2019: unresolved external symbol "__imp__recvfrom@24" referenced in function ""public: void __thiscall Router::Run(void)" (?Run@Router@@QAEXXZ)".
error LNK2019: unresolved external symbol "__imp__select@20" referenced in function ""public: void __thiscall Router::Run(void)" (?Run@Router@@QAEXXZ)".
error LNK2019: unresolved external symbol "__imp__sendto@24" referenced in function ""public: void __thiscall Router::Run(void)" (?Run@Router@@QAEXXZ)".
error LNK2019: unresolved external symbol "__imp__socket@12" referenced in function "__catch$??0Router@@QAE@PBD@Z$0".
error LNK2019: unresolved external symbol "__imp__gethostbyname@4" referenced in function "__catch$??0Router@@QAE@PBD@Z$0".
error LNK2019: unresolved external symbol "__imp__gethostname@8" referenced in function "__catch$??0Router@@QAE@PBD@Z$0".
error LNK2019: unresolved external symbol "__imp__WSAStartup@8" referenced in function ""public: __thiscall Router::Router(char const *)" (??0Router@@QAE@PBD@Z)".
error LNK2019: unresolved external symbol "__imp__WSACleanup@0" referenced in function ""public: __thiscall Router::~Router(void)" (??1Router@@QAE@XZ)".
error LNK2019: unresolved external symbol "__imp__WSAGetLastError@0" referenced in function "__catch$??0Router@@QAE@PBD@Z$0".

我们现在必须识别定义这些符号的库。将它们的名称放入搜索引擎可以告诉我它们都是winsocket2 API的一部分。给定here的示例告诉我们相应的库称为Ws2_32.lib

我们现在必须告诉编译器针对该库进行链接。具体步骤取决于您的编译器/ IDE。您表示正在使用Code :: Blocks。请参阅here所提供的说明,以了解如何在Code :: Blocks中添加库(似乎Code :: Blocks想要不带后缀.lib的库名,因此名称应为{{1} },而不是Ws2_32

链接到该库后,您的代码成功编译。