如题要c++写的,可穿透各种网关的

解决方案 »

  1.   

    P2P网络技术原理与C++开发案例, 36元
      

  2.   

    穿透各种网关,nb啊。要打洞成功率100%m么?QQ也不一定能保证吧
      

  3.   

    STUN+TURN+UPNP实现这几个就差不多了
      

  4.   

    /* P2P 程序客户端
     * 
     * 文件名:P2PClient.c
     *
     * 日期:2004-5-21
     *
     * 作者:shootingstars([email protected])
     *
     */#pragma comment(lib,"ws2_32.lib")#include "windows.h"
    #include "..\proto.h"
    #include "..\Exception.h"
    #include <iostream>
    using namespace std;UserList ClientList;#define COMMANDMAXC 256
    #define MAXRETRY    5SOCKET PrimaryUDP;
    char UserName[10];
    char ServerIP[20];bool RecvedACK;void InitWinSock()
    {
    WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
    printf("Windows sockets 2.2 startup");
    throw Exception("");
    }
    else{
    printf("Using %s (Status: %s)\n",
    wsaData.szDescription, wsaData.szSystemStatus);
    printf("with API versions %d.%d to %d.%d\n\n",
    LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
    LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
    }
    }SOCKET mksock(int type)
    {
    SOCKET sock = socket(AF_INET, type, 0);
    if (sock < 0)
    {
            printf("create socket error");
    throw Exception("");
    }
    return sock;
    }stUserListNode GetUser(char *username)
    {
    for(UserList::iterator UserIterator=ClientList.begin();
    UserIterator!=ClientList.end();
    ++UserIterator)
    {
    if( strcmp( ((*UserIterator)->userName), username) == 0 )
    return *(*UserIterator);
    }
    throw Exception("not find this user");
    }void BindSock(SOCKET sock)
    {
    sockaddr_in sin;
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    sin.sin_family = AF_INET;
    sin.sin_port = 0;

    if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    throw Exception("bind error");
    }void ConnectToServer(SOCKET sock,char *username, char *serverip)
    {
    sockaddr_in remote;
    remote.sin_addr.S_un.S_addr = inet_addr(serverip);
    remote.sin_family = AF_INET;
    remote.sin_port = htons(SERVER_PORT);

    stMessage sendbuf;
    sendbuf.iMessageType = LOGIN;
    strncpy(sendbuf.message.loginmember.userName, username, 10); sendto(sock, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote,sizeof(remote)); int usercount;
    int fromlen = sizeof(remote);
    int iread = recvfrom(sock, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
    if(iread<=0)
    {
    throw Exception("Login error\n");
    } // 登录到服务端后,接收服务端发来的已经登录的用户的信息
    cout<<"Have "<<usercount<<" users logined server:"<<endl;
    for(int i = 0;i<usercount;i++)
    {
    stUserListNode *node = new stUserListNode;
    recvfrom(sock, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
    ClientList.push_back(node);
    cout<<"Username:"<<node->userName<<endl;
    in_addr tmp;
    tmp.S_un.S_addr = htonl(node->ip);
    cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
    cout<<"UserPort:"<<node->port<<endl;
    cout<<""<<endl;
    }
    }void OutputUsage()
    {
    cout<<"You can input you command:\n"
    <<"Command Type:\"send\",\"exit\",\"getu\"\n"
    <<"Example : send Username Message\n"
    <<"          exit\n"
    <<"          getu\n"
    <<endl;
    }/* 这是主要的函数:发送一个消息给某个用户(C)
     *流程:直接向某个用户的外网IP发送消息,如果此前没有联系过
     *      那么此消息将无法发送,发送端等待超时。
     *      超时后,发送端将发送一个请求信息到服务端,
     *      要求服务端发送给客户C一个请求,请求C给本机发送打洞消息
     *      以上流程将重复MAXRETRY次
     */
    bool SendMessageTo(char *UserName, char *Message)
    {
    char realmessage[256];
    unsigned int UserIP;
    unsigned short UserPort;
    bool FindUser = false;
    for(UserList::iterator UserIterator=ClientList.begin();
    UserIterator!=ClientList.end();
    ++UserIterator)
    {
    if( strcmp( ((*UserIterator)->userName), UserName) == 0 )
    {
    UserIP = (*UserIterator)->ip;
    UserPort = (*UserIterator)->port;
    FindUser = true;
    }
    } if(!FindUser)
    return false; strcpy(realmessage, Message);
    for(int i=0;i<MAXRETRY;i++)
    {
    RecvedACK = false; sockaddr_in remote;
    remote.sin_addr.S_un.S_addr = htonl(UserIP);
    remote.sin_family = AF_INET;
    remote.sin_port = htons(UserPort);
    stP2PMessage MessageHead;
    MessageHead.iMessageType = P2PMESSAGE;
    MessageHead.iStringLen = (int)strlen(realmessage)+1;
    int isend = sendto(PrimaryUDP, (const char *)&MessageHead, sizeof(MessageHead), 0, (const sockaddr*)&remote, sizeof(remote));
    isend = sendto(PrimaryUDP, (const char *)&realmessage, MessageHead.iStringLen, 0, (const sockaddr*)&remote, sizeof(remote));

    // 等待接收线程将此标记修改
    for(int j=0;j<10;j++)
    {
    if(RecvedACK)
    return true;
    else
    Sleep(300);
    } // 没有接收到目标主机的回应,认为目标主机的端口映射没有
    // 打开,那么发送请求信息给服务器,要服务器告诉目标主机
    // 打开映射端口(UDP打洞)
    sockaddr_in server;
    server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
    server.sin_family = AF_INET;
    server.sin_port = htons(SERVER_PORT);

    stMessage transMessage;
    transMessage.iMessageType = P2PTRANS;
    strcpy(transMessage.message.translatemessage.userName, UserName); sendto(PrimaryUDP, (const char*)&transMessage, sizeof(transMessage), 0, (const sockaddr*)&server, sizeof(server));
    Sleep(100);// 等待对方先发送信息。
    }
    return false;
    }// 解析命令,暂时只有exit和send命令
    // 新增getu命令,获取当前服务器的所有用户
    void ParseCommand(char * CommandLine)
    {
    if(strlen(CommandLine)<4)
    return;
    char Command[10];
    strncpy(Command, CommandLine, 4);
    Command[4]='\0'; if(strcmp(Command,"exit")==0)
    {
    stMessage sendbuf;
    sendbuf.iMessageType = LOGOUT;
    strncpy(sendbuf.message.logoutmember.userName, UserName, 10);
    sockaddr_in server;
    server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
    server.sin_family = AF_INET;
    server.sin_port = htons(SERVER_PORT); sendto(PrimaryUDP,(const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr *)&server, sizeof(server));
    shutdown(PrimaryUDP, 2);
    closesocket(PrimaryUDP);
    exit(0);
    }
    else if(strcmp(Command,"send")==0)
    {
    char sendname[20];
    char message[COMMANDMAXC];
    int i;
    for(i=5;;i++)
    {
    if(CommandLine[i]!=' ')
    sendname[i-5]=CommandLine[i];
    else
    {
    sendname[i-5]='\0';
    break;
    }
    }
    strcpy(message, &(CommandLine[i+1]));
    if(SendMessageTo(sendname, message))
    printf("Send OK!\n");
    else 
    printf("Send Failure!\n");
    }
    else if(strcmp(Command,"getu")==0)
    {
    int command = GETALLUSER;
    sockaddr_in server;
    server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
    server.sin_family = AF_INET;
    server.sin_port = htons(SERVER_PORT); sendto(PrimaryUDP,(const char*)&command, sizeof(command), 0, (const sockaddr *)&server, sizeof(server));
    }
    }// 接受消息线程
    DWORD WINAPI RecvThreadProc(LPVOID lpParameter)
    {
    sockaddr_in remote;
    int sinlen = sizeof(remote);
    stP2PMessage recvbuf;
    for(;;)
    {
    int iread = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(recvbuf), 0, (sockaddr *)&remote, &sinlen);
    if(iread<=0)
    {
    printf("recv error\n");
    continue;
    }
    switch(recvbuf.iMessageType)
    {
    case P2PMESSAGE:
    {
    // 接收到P2P的消息
    char *comemessage= new char[recvbuf.iStringLen];
    int iread1 = recvfrom(PrimaryUDP, comemessage, 256, 0, (sockaddr *)&remote, &sinlen);
    comemessage[iread1-1] = '\0';
    if(iread1<=0)
    throw Exception("Recv Message Error\n");
    else
    {
    printf("Recv a Message:%s\n",comemessage);

    stP2PMessage sendbuf;
    sendbuf.iMessageType = P2PMESSAGEACK;
    sendto(PrimaryUDP, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote, sizeof(remote));
    } delete []comemessage;
    break; }
    case P2PSOMEONEWANTTOCALLYOU:
    {
    // 接收到打洞命令,向指定的IP地址打洞
    printf("Recv p2someonewanttocallyou data\n");
    sockaddr_in remote;
    remote.sin_addr.S_un.S_addr = htonl(recvbuf.iStringLen);
    remote.sin_family = AF_INET;
    remote.sin_port = htons(recvbuf.Port); // UDP hole punching
    stP2PMessage message;
    message.iMessageType = P2PTRASH;
    sendto(PrimaryUDP, (const char *)&message, sizeof(message), 0, (const sockaddr*)&remote, sizeof(remote));
                    
    break;
    }
    case P2PMESSAGEACK:
    {
    // 发送消息的应答
    RecvedACK = true;
    break;
    }
    case P2PTRASH:
    {
    // 对方发送的打洞消息,忽略掉。
    //do nothing ...
    printf("Recv p2ptrash data\n");
    break;
    }
    case GETALLUSER:
    {
    int usercount;
    int fromlen = sizeof(remote);
    int iread = recvfrom(PrimaryUDP, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
    if(iread<=0)
    {
    throw Exception("Login error\n");
    }

    ClientList.clear(); cout<<"Have "<<usercount<<" users logined server:"<<endl;
    for(int i = 0;i<usercount;i++)
    {
    stUserListNode *node = new stUserListNode;
    recvfrom(PrimaryUDP, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
    ClientList.push_back(node);
    cout<<"Username:"<<node->userName<<endl;
    in_addr tmp;
    tmp.S_un.S_addr = htonl(node->ip);
    cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
    cout<<"UserPort:"<<node->port<<endl;
    cout<<""<<endl;
    }
    break;
    }
    }
    }
    }
    int main(int argc, char* argv[])
    {
    try
    {
    InitWinSock();

    PrimaryUDP = mksock(SOCK_DGRAM);
    BindSock(PrimaryUDP); cout<<"Please input server ip:";
    cin>>ServerIP; cout<<"Please input your name:";
    cin>>UserName; ConnectToServer(PrimaryUDP, UserName, ServerIP); HANDLE threadhandle = CreateThread(NULL, 0, RecvThreadProc, NULL, NULL, NULL);
    CloseHandle(threadhandle);
    OutputUsage(); for(;;)
    {
    char Command[COMMANDMAXC];
    gets(Command);
    ParseCommand(Command);
    }
    }
    catch(Exception &e)
    {
    printf(e.GetMessage());
    return 1;
    }
    return 0;
    }        
      

  5.   

    /* P2P 程序服务端
     * 
     * 文件名:P2PServer.c
     *
     * 日期:2004-5-21
     *
     * 作者:shootingstars([email protected])
     *
     */
    #pragma comment(lib, "ws2_32.lib")#include "windows.h"
    #include "..\proto.h"
    #include "..\Exception.h"UserList ClientList;void InitWinSock()
    {
    WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
    printf("Windows sockets 2.2 startup");
    throw Exception("");
    }
    else{
    printf("Using %s (Status: %s)\n",
    wsaData.szDescription, wsaData.szSystemStatus);
    printf("with API versions %d.%d to %d.%d\n\n",
    LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
    LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));

    }
    }SOCKET mksock(int type)
    {
    SOCKET sock = socket(AF_INET, type, 0);
    if (sock < 0)
    {
            printf("create socket error");
    throw Exception("");
    }
    return sock;
    }stUserListNode GetUser(char *username)
    {
    for(UserList::iterator UserIterator=ClientList.begin();
    UserIterator!=ClientList.end();
    ++UserIterator)
    {
    if( strcmp( ((*UserIterator)->userName), username) == 0 )
    return *(*UserIterator);
    }
    throw Exception("not find this user");
    }int main(int argc, char* argv[])
    {
    try{
    InitWinSock();

    SOCKET PrimaryUDP;
    PrimaryUDP = mksock(SOCK_DGRAM); sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port= htons(SERVER_PORT); 
    local.sin_addr.s_addr = htonl(INADDR_ANY);
    int nResult=bind(PrimaryUDP,(sockaddr*)&local,sizeof(sockaddr));
    if(nResult==SOCKET_ERROR)
    throw Exception("bind error"); sockaddr_in sender;
    stMessage recvbuf;
    memset(&recvbuf,0,sizeof(stMessage)); // 开始主循环.
    // 主循环负责下面几件事情:
    // 一:读取客户端登陆和登出消息,记录客户列表
    // 二:转发客户p2p请求
    for(;;)
    {
    int dwSender = sizeof(sender);
    int ret = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(stMessage), 0, (sockaddr *)&sender, &dwSender);
    if(ret <= 0)
    {
    printf("recv error");
    continue;
    }
    else
    {
    int messageType = recvbuf.iMessageType;
    switch(messageType){
    case LOGIN:
    {
    //  将这个用户的信息记录到用户列表中
    printf("has a user login : %s\n", recvbuf.message.loginmember.userName);
    stUserListNode *currentuser = new stUserListNode();
    strcpy(currentuser->userName, recvbuf.message.loginmember.userName);
    currentuser->ip = ntohl(sender.sin_addr.S_un.S_addr);
    currentuser->port = ntohs(sender.sin_port);

    ClientList.push_back(currentuser); // 发送已经登陆的客户信息
    int nodecount = (int)ClientList.size();
    sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender));
    for(UserList::iterator UserIterator=ClientList.begin();
    UserIterator!=ClientList.end();
    ++UserIterator)
    {
    sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode), 0, (const sockaddr*)&sender, sizeof(sender)); 
    } break;
    }
    case LOGOUT:
    {
    // 将此客户信息删除
    printf("has a user logout : %s\n", recvbuf.message.logoutmember.userName);
    UserList::iterator removeiterator = NULL;
    for(UserList::iterator UserIterator=ClientList.begin();
    UserIterator!=ClientList.end();
    ++UserIterator)
    {
    if( strcmp( ((*UserIterator)->userName), recvbuf.message.logoutmember.userName) == 0 )
    {
    removeiterator = UserIterator;
    break;
    }
    }
    if(removeiterator != NULL)
    ClientList.remove(*removeiterator);
    break;
    }
    case P2PTRANS:
    {
    // 某个客户希望服务端向另外一个客户发送一个打洞消息
    printf("%s wants to p2p %s\n",inet_ntoa(sender.sin_addr),recvbuf.message.translatemessage.userName);
    stUserListNode node = GetUser(recvbuf.message.translatemessage.userName);
    sockaddr_in remote;
    remote.sin_family=AF_INET;
    remote.sin_port= htons(node.port); 
    remote.sin_addr.s_addr = htonl(node.ip); in_addr tmp;
    tmp.S_un.S_addr = htonl(node.ip);
    printf("the address is %s,and port is %d\n",inet_ntoa(tmp), node.port); stP2PMessage transMessage;
    transMessage.iMessageType = P2PSOMEONEWANTTOCALLYOU;
    transMessage.iStringLen = ntohl(sender.sin_addr.S_un.S_addr);
    transMessage.Port = ntohs(sender.sin_port);
                            
    sendto(PrimaryUDP,(const char*)&transMessage, sizeof(transMessage), 0, (const sockaddr *)&remote, sizeof(remote)); break;
    }

    case GETALLUSER:
    {
    int command = GETALLUSER;
    sendto(PrimaryUDP, (const char*)&command, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender)); int nodecount = (int)ClientList.size();
    sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender)); for(UserList::iterator UserIterator=ClientList.begin();
    UserIterator!=ClientList.end();
    ++UserIterator)
    {
    sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode), 0, (const sockaddr*)&sender, sizeof(sender)); 
    }
    break;
    }
    }
    }
    } }
    catch(Exception &e)
    {
    printf(e.GetMessage());
    return 1;
    } return 0;
    }/* 异常类
     *
     * 文件名:Exception.h
     *
     * 日期:2004.5.5
     *
     * 作者:shootingstars([email protected])
     */#ifndef __HZH_Exception__
    #define __HZH_Exception__#define EXCEPTION_MESSAGE_MAXLEN 256
    #include "string.h"class Exception
    {
    private:
    char m_ExceptionMessage[EXCEPTION_MESSAGE_MAXLEN];
    public:
    Exception(char *msg)
    {
    strncpy(m_ExceptionMessage, msg, EXCEPTION_MESSAGE_MAXLEN);
    } char *GetMessage()
    {
    return m_ExceptionMessage;
    }
    };#endif/* P2P 程序传输协议
     * 
     * 文件名:proto.h
     *
     * 日期:2004-5-21
     *
     * 作者:shootingstars([email protected])
     *
     */#pragma once
    #include <list>// 定义iMessageType的值
    #define LOGIN 1
    #define LOGOUT 2
    #define P2PTRANS 3
    #define GETALLUSER  4// 服务器端口
    #define SERVER_PORT 2280// Client登录时向服务器发送的消息
    struct stLoginMessage
    {
    char userName[10];
    char password[10];
    };// Client注销时发送的消息
    struct stLogoutMessage
    {
    char userName[10];
    };// Client向服务器请求另外一个Client(userName)向自己方向发送UDP打洞消息
    struct stP2PTranslate
    {
    char userName[10];
    };// Client向服务器发送的消息格式
    struct stMessage
    {
    int iMessageType;
    union _message
    {
    stLoginMessage loginmember;
    stLogoutMessage logoutmember;
    stP2PTranslate translatemessage;
    }message;
    };// 客户节点信息
    struct stUserListNode
    {
    char userName[10];
    unsigned int ip;
    unsigned short port;
    };// Server向Client发送的消息
    struct stServerToClient
    {
    int iMessageType;
    union _message
    {
    stUserListNode user;
    }message;};//======================================
    // 下面的协议用于客户端之间的通信
    //======================================
    #define P2PMESSAGE 100               // 发送消息
    #define P2PMESSAGEACK 101            // 收到消息的应答
    #define P2PSOMEONEWANTTOCALLYOU 102  // 服务器向客户端发送的消息
                                         // 希望此客户端发送一个UDP打洞包
    #define P2PTRASH        103          // 客户端发送的打洞包,接收端应该忽略此消息// 客户端之间发送消息格式
    struct stP2PMessage
    {
    int iMessageType;
    int iStringLen;         // or IP address
    unsigned short Port; 
    };using namespace std;
    typedef list<stUserListNode *> UserList;
      

  6.   

    要c++写的,可穿透各种网关的
    ====================================================
    你丫的开玩笑呢!?
    就20分。
    所有NAT类型!?
    你们啥学校啊!?要求所有NAT类型太神了,我保证。是你需求没有听好。
      

  7.   

    QT examples中就有一个bt下载的
      

  8.   

    我写的一个FAW SDK库
    可以基本实现P2P传输
    不过是用我的库函数执行
    代码不给,哈哈
    http://cid-f9bdd17c2d0b67e5.skydrive.live.com/self.aspx/.Public/FawSdkC.zip
    里面包括了两个如何使用的示范工程
    VS2005或者以上版本直接可以打开