P2P之UDP穿透NAT的原理與實現(實現部分)

  1. // P2P程序服務端 
  2. // 文件名:P2PServer.cpp
  3. #include <windows.h>
  4. #include "proto.h"
  5. #include "Exception.h"
  6. #pragma comment(lib, "ws2_32.lib")
  7. UserList ClientList;
  8. void InitWinSock()
  9. {
  10.     WSADATA wsaData;
  11.     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  12.     {
  13.         printf("Windows sockets 2.2 startup") ;
  14.         throw Exception("") ;
  15.     }
  16.     else
  17.     {
  18.         printf("Using %s (Status: %s)/n",
  19.                 wsaData.szDescription, wsaData.szSystemStatus) ;
  20.         printf("with API versions %d.%d to %d.%d/n/n",
  21.                 LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
  22.                 LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)) ;
  23.     }
  24. }
  25. SOCKET mksock(int type)
  26. {
  27.     SOCKET sock = socket(AF_INET, type, 0) ;
  28.     if (sock < 0)
  29.     {
  30.         printf("create socket error") ;
  31.         throw Exception("") ;
  32.     }
  33.     return sock;
  34. }
  35. stUserListNode GetUser(char *username)
  36. {
  37.     for(UserList::iterator UserIterator=ClientList.begin();
  38.             UserIterator!=ClientList.end(); ++UserIterator)
  39.     {
  40.         if( strcmp( ((*UserIterator)->userName), username) == 0 )
  41.             return *(*UserIterator) ;
  42.     }
  43.     throw Exception("not find this user") ;
  44. }
  45. int main(int argc, char* argv[])
  46. {
  47.     try
  48.     {
  49.         InitWinSock();
  50.   
  51.         SOCKET PrimaryUDP;
  52.         PrimaryUDP = mksock(SOCK_DGRAM);
  53.         sockaddr_in local;
  54.         local.sin_family=AF_INET;
  55.         local.sin_port = htons(SERVER_PORT); 
  56.         local.sin_addr.s_addr = htonl(INADDR_ANY);
  57.         int nResult = bind(PrimaryUDP, (sockaddr*)&local, sizeof(sockaddr)) ;
  58.         if(nResult == SOCKET_ERROR)
  59.             throw Exception("bind error");
  60.         sockaddr_in sender;
  61.         stMessage recvbuf;
  62.         memset(&recvbuf, 0, sizeof(stMessage)) ;
  63.   // 開始主循環.
  64.   // 主循環負責下面幾件事情:
  65.   // 一:讀取客戶端登陸和登出消息,記錄客戶列表
  66.   // 二:轉發客戶p2p請求
  67.         for(; ;)
  68.         {
  69.             int dwSender = sizeof(sender);
  70.             int ret = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(stMessage),
  71.                     0, (sockaddr *)&sender, &dwSender) ;
  72.             if(ret <= 0)
  73.             {
  74.                 printf("recv error");
  75.                 continue;
  76.             }
  77.             else
  78.             {
  79.                 int messageType = recvbuf.iMessageType ;
  80.                 switch(messageType)
  81.                 {
  82.                 case LOGIN:
  83.                 {
  84.                     //  將這個用戶的信息記錄到用戶列表中
  85.                     printf("has a user login : %s/n", recvbuf.message.loginmember.userName);
  86.                     stUserListNode *currentuser = new stUserListNode();
  87.                     strcpy(currentuser->userName, recvbuf.message.loginmember.userName);
  88.                     currentuser->ip = ntohl(sender.sin_addr.S_un.S_addr);
  89.                     currentuser->port = ntohs(sender.sin_port);
  90.       
  91.                     ClientList.push_back(currentuser);
  92.                     // 發送已經登陸的客戶信息
  93.                     int nodecount = (int)ClientList.size();
  94.                     sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0,
  95.                             (const sockaddr*)&sender, sizeof(sender)) ;
  96.                     for(UserList::iterator UserIterator=ClientList.begin();
  97.                             UserIterator!=ClientList.end(); ++UserIterator)
  98.                     {
  99.                         sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode),
  100.                                 0, (const sockaddr*)&sender, sizeof(sender)) ; 
  101.                     }
  102.                     break;
  103.                 }
  104.                 case LOGOUT:
  105.                 {
  106.                     // 將此客戶信息刪除
  107.                     printf("has a user logout : %s/n", recvbuf.message.logoutmember.userName);
  108.                     UserList::iterator removeiterator = NULL;
  109.                     for(UserList::iterator UserIterator=ClientList.begin();
  110.                             UserIterator!=ClientList.end(); ++UserIterator)
  111.                     {
  112.                         if( strcmp( ((*UserIterator)->userName),
  113.                                 recvbuf.message.logoutmember.userName) == 0 )
  114.                         {
  115.                             removeiterator = UserIterator;
  116.                             break;
  117.                         }
  118.                     }
  119.                     if(removeiterator != NULL)
  120.                         ClientList.remove(*removeiterator);
  121.                     break;
  122.                 }
  123.                 case P2PTRANS:
  124.                 {
  125.                     // 某個客戶希望服務端向另外一個客戶發送一個打洞消息
  126.                     printf("%s wants to p2p %s/n",inet_ntoa(sender.sin_addr),
  127.                             recvbuf.message.translatemessage.userName);
  128.                     stUserListNode node = GetUser(recvbuf.message.translatemessage.userName);
  129.                     sockaddr_in remote;
  130.                     remote.sin_family=AF_INET;
  131.                     remote.sin_port= htons(node.port); 
  132.                     remote.sin_addr.s_addr = htonl(node.ip);
  133.                     in_addr tmp;
  134.                     tmp.S_un.S_addr = htonl(node.ip);
  135.                     printf("the address is %s,and port is %d/n",inet_ntoa(tmp), node.port);
  136.                     stP2PMessage transMessage;
  137.                     transMessage.iMessageType = P2PSOMEONEWANTTOCALLYOU;
  138.                     transMessage.iStringLen = ntohl(sender.sin_addr.S_un.S_addr);
  139.                     transMessage.Port = ntohs(sender.sin_port);
  140.                         
  141.                     sendto(PrimaryUDP,(const char*)&transMessage, sizeof(transMessage), 0,
  142.                             (const sockaddr *)&remote, sizeof(remote)) ;
  143.                     break;
  144.                 }
  145.     
  146.                 case GETALLUSER:
  147.                 {
  148.                     int command = GETALLUSER;
  149.                     sendto(PrimaryUDP, (const char*)&command, sizeof(int), 0,
  150.                             (const sockaddr*)&sender, sizeof(sender)) ;
  151.                     int nodecount = (int)ClientList.size();
  152.                     sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0,
  153.                             (const sockaddr*)&sender, sizeof(sender)) ;
  154.                     for(UserList::iterator UserIterator=ClientList.begin();
  155.                             UserIterator!=ClientList.end(); ++UserIterator)
  156.                     {
  157.                         sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode),
  158.                                 0, (const sockaddr*)&sender, sizeof(sender)); 
  159.                     }
  160.                     break;
  161.                 }
  162.                 } //end switch
  163.             } //end else
  164.         } //end for
  165.     } //end try
  166.     catch(Exception &e)
  167.     {
  168.         printf(e.GetMessage()) ;
  169.         return 1 ;
  170.     }
  171.     return 0;
  172. }

 

  1. // P2P 程序客戶端
  2. // 文件名:P2PClient.c
  3. #include <windows.h>
  4. #include "proto.h"
  5. #include "Exception.h"
  6. #include <iostream>
  7. #define COMMANDMAXC 256
  8. #define MAXRETRY    5
  9. #pragma comment(lib,"ws2_32.lib")
  10. using namespace std;
  11. UserList ClientList;
  12. SOCKET PrimaryUDP;
  13. char UserName[10];
  14. char ServerIP[20];
  15. bool RecvedACK;
  16. void InitWinSock()
  17. {
  18.     WSADATA wsaData ;
  19.     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  20.     {
  21.         printf("Windows sockets 2.2 startup");
  22.         throw Exception("");
  23.     }
  24.     else
  25.     {
  26.         printf("Using %s (Status: %s)/n",
  27.                 wsaData.szDescription, wsaData.szSystemStatus);
  28.         printf("with API versions %d.%d to %d.%d/n/n",
  29.                 LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
  30.                 LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
  31.     }
  32. }
  33. SOCKET mksock(int type)
  34. {
  35.     SOCKET sock = socket(AF_INET, type, 0);
  36.     if (sock < 0)
  37.     {
  38.         printf("create socket error");
  39.         throw Exception("");
  40.     }
  41.     return sock;
  42. }
  43. stUserListNode GetUser(char *username)
  44. {
  45.     for(UserList::iterator UserIterator=ClientList.begin();
  46.             UserIterator!=ClientList.end(); ++UserIterator)
  47.     {
  48.         if( strcmp( ((*UserIterator)->userName), username) == 0 )
  49.             return *(*UserIterator);
  50.     }
  51.     throw Exception("not find this user");
  52. }
  53. void BindSock(SOCKET sock)
  54. {
  55.     sockaddr_in sin;
  56.     sin.sin_addr.S_un.S_addr = INADDR_ANY;
  57.     sin.sin_family = AF_INET;
  58.     sin.sin_port = 0;
  59.     if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
  60.         throw Exception("bind error") ;
  61. }
  62. void ConnectToServer(SOCKET sock,char *username, char *serverip)
  63. {
  64.     sockaddr_in remote;
  65.     remote.sin_addr.S_un.S_addr = inet_addr(serverip);
  66.     remote.sin_family = AF_INET;
  67.     remote.sin_port = htons(SERVER_PORT);
  68.     stMessage sendbuf;
  69.     sendbuf.iMessageType = LOGIN;
  70.     strncpy(sendbuf.message.loginmember.userName, username, 10);
  71.     sendto(sock, (const char*)&sendbuf, sizeof(sendbuf), 0,
  72.             (const sockaddr*)&remote, sizeof(remote)) ;
  73.     int usercount;
  74.     int fromlen = sizeof(remote);
  75.     int iread = recvfrom(sock, (char *)&usercount, sizeof(int), 0,
  76.             (sockaddr *)&remote, &fromlen);
  77.     if(iread <= 0)
  78.     {
  79.         throw Exception("Login error/n");
  80.     }
  81.     // 登錄到服務端後,接收服務端發來的已經登錄的用戶的信息
  82.     cout<<"Have "<<usercount<<" users logined server:"<<endl ;
  83.     for(int i = 0;i<usercount;i++)
  84.     {
  85.         stUserListNode *node = new stUserListNode;
  86.         recvfrom(sock, (char*)node, sizeof(stUserListNode), 0,
  87.                 (sockaddr *)&remote, &fromlen);
  88.         ClientList.push_back(node);
  89.         cout<<"Username:"<<node->userName<<endl;
  90.         in_addr tmp;
  91.         tmp.S_un.S_addr = htonl(node->ip);
  92.         cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
  93.         cout<<"UserPort:"<<node->port<<endl;
  94.         cout<<""<<endl;
  95.     }
  96. }
  97. void OutputUsage()
  98. {
  99.     cout<<"You can input you command:/n"
  100.         <<"Command Type:/"send/",/"exit/",/"getu/"/n"
  101.         <<"Example : send Username Message/n"
  102.         <<"          exit/n"
  103.         <<"          getu/n"
  104.         <<endl;
  105. }
  106. /* 這是主要的函數:發送一個消息給某個用戶(C)
  107. *  流程:直接向某個用戶的外網IP發送消息,如果此前沒有聯繫過
  108. *  那麼此消息將無法發送,發送端等待超時。
  109. *  超時後,發送端將發送一個請求信息到服務端,
  110. *  要求服務端發送給客戶C一個請求,請求C給本機發送打洞消息
  111. *  以上流程將重複MAXRETRY次
  112. */
  113. bool SendMessageTo(char *UserName, char *Message)
  114. {
  115.     char realmessage[256];
  116.     unsigned int UserIP;
  117.     unsigned short UserPort;
  118.     bool FindUser = false;
  119.     for(UserList::iterator UserIterator=ClientList.begin();
  120.             UserIterator!=ClientList.end(); ++UserIterator)
  121.     {
  122.         if( strcmp( ((*UserIterator)->userName), UserName) == 0 )
  123.         {
  124.             UserIP = (*UserIterator)->ip;
  125.             UserPort = (*UserIterator)->port;
  126.             FindUser = true;
  127.         }
  128.     }
  129.     if(!FindUser)
  130.         return false;
  131.     strcpy(realmessage, Message) ;
  132.     for(int i=0;i<MAXRETRY;i++)
  133.     {
  134.         RecvedACK = false;
  135.         sockaddr_in remote;
  136.         remote.sin_addr.S_un.S_addr = htonl(UserIP);
  137.         remote.sin_family = AF_INET;
  138.         remote.sin_port = htons(UserPort);
  139.         stP2PMessage MessageHead;
  140.         MessageHead.iMessageType = P2PMESSAGE;
  141.         MessageHead.iStringLen = (int)strlen(realmessage)+1;
  142.         int isend = sendto(PrimaryUDP, (const char *)&MessageHead,
  143.                 sizeof(MessageHead), 0, (const sockaddr*)&remote,
  144.                 sizeof(remote));
  145.         isend = sendto(PrimaryUDP, (const char *)&realmessage,
  146.                 MessageHead.iStringLen, 0, (const sockaddr*)&remote,
  147.                 sizeof(remote));
  148.   
  149.         // 等待接收線程將此標記修改
  150.         for(int j=0;j<10;j++)
  151.         {
  152.             if(RecvedACK)
  153.                 return true;
  154.             else
  155.                 Sleep(300);
  156.         }
  157.   // 沒有接收到目標主機的迴應,認爲目標主機的端口映射沒有
  158.   // 打開,那麼發送請求信息給服務器,要服務器告訴目標主機
  159.   // 打開映射端口(UDP打洞)
  160.         sockaddr_in server;
  161.         server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
  162.         server.sin_family = AF_INET;
  163.         server.sin_port = htons(SERVER_PORT);
  164.         stMessage transMessage;
  165.         transMessage.iMessageType = P2PTRANS;
  166.         strcpy(transMessage.message.translatemessage.userName, UserName);
  167.         sendto(PrimaryUDP, (const char*)&transMessage, sizeof(transMessage),
  168.                 0, (const sockaddr*)&server, sizeof(server)) ;
  169.         Sleep(100);// 等待對方先發送信息。
  170.     }
  171.     return false ;
  172. }
  173. // 解析命令,暫時只有exit和send命令
  174. // 新增getu命令,獲取當前服務器的所有用戶
  175. void ParseCommand(char * CommandLine)
  176. {
  177.     if(strlen(CommandLine)<4)
  178.         return;
  179.     char Command[10];
  180.     strncpy(Command, CommandLine, 4);
  181.     Command[4]='/0';
  182.     if(strcmp(Command,"exit")==0)
  183.     {
  184.         stMessage sendbuf;
  185.         sendbuf.iMessageType = LOGOUT;
  186.         strncpy(sendbuf.message.logoutmember.userName, UserName, 10);
  187.         sockaddr_in server;
  188.         server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
  189.         server.sin_family = AF_INET;
  190.         server.sin_port = htons(SERVER_PORT);
  191.         sendto(PrimaryUDP,(const char*)&sendbuf, sizeof(sendbuf), 0,
  192.                 (const sockaddr *)&server, sizeof(server)) ;
  193.         shutdown(PrimaryUDP, 2);
  194.         closesocket(PrimaryUDP);
  195.         exit(0);
  196.     }
  197.     else if(strcmp(Command,"send")==0)
  198.     {
  199.         char sendname[20];
  200.         char message[COMMANDMAXC];
  201.         int i;
  202.         for(i=5;;i++)
  203.         {
  204.             if(CommandLine[i]!=' ')
  205.                 sendname[i-5]=CommandLine[i];
  206.             else
  207.             {
  208.                 sendname[i-5]='/0';
  209.                 break;
  210.             }
  211.         }
  212.         strcpy(message, &(CommandLine[i+1]));
  213.         if(SendMessageTo(sendname, message))
  214.             printf("Send OK!/n");
  215.         else 
  216.             printf("Send Failure!/n");
  217.     }
  218.     else if(strcmp(Command,"getu")==0)
  219.     {
  220.         int command = GETALLUSER;
  221.         sockaddr_in server;
  222.         server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
  223.         server.sin_family = AF_INET;
  224.         server.sin_port = htons(SERVER_PORT);
  225.         sendto(PrimaryUDP,(const char*)&command, sizeof(command), 0,
  226.                  (const sockaddr *)&server, sizeof(server)) ;
  227.     }
  228. }
  229. // 接受消息線程
  230. DWORD WINAPI RecvThreadProc(LPVOID lpParameter)
  231. {
  232.     sockaddr_in remote;
  233.     int sinlen = sizeof(remote);
  234.     stP2PMessage recvbuf;
  235.     for(; ;)
  236.     {
  237.         int iread = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(recvbuf),
  238.                 0, (sockaddr *)&remote, &sinlen);
  239.         if(iread<=0)
  240.         {
  241.             printf("recv error/n");
  242.             continue;
  243.         }
  244.         switch(recvbuf.iMessageType)
  245.         {
  246.         case P2PMESSAGE:
  247.         {
  248.             // 接收到P2P的消息
  249.             char *comemessage= new char[recvbuf.iStringLen];
  250.             int iread1 = recvfrom(PrimaryUDP, comemessage, 256, 0,
  251.                     (sockaddr *)&remote, &sinlen) ;
  252.             comemessage[iread1-1] = '/0';
  253.             if(iread1<=0)
  254.                 throw Exception("Recv Message Error/n");
  255.             else
  256.             {
  257.                 printf("Recv a Message:%s/n",comemessage);
  258.      
  259.                 stP2PMessage sendbuf;
  260.                 sendbuf.iMessageType = P2PMESSAGEACK;
  261.                 sendto(PrimaryUDP, (const char*)&sendbuf, sizeof(sendbuf), 0,
  262.                         (const sockaddr*)&remote, sizeof(remote)) ;
  263.             }
  264.             delete []comemessage;
  265.             break;
  266.         }
  267.         case P2PSOMEONEWANTTOCALLYOU:
  268.         {
  269.             // 接收到打洞命令,向指定的IP地址打洞
  270.             printf("Recv p2someonewanttocallyou data/n");
  271.             sockaddr_in remote;
  272.             remote.sin_addr.S_un.S_addr = htonl(recvbuf.iStringLen);
  273.             remote.sin_family = AF_INET;
  274.             remote.sin_port = htons(recvbuf.Port);
  275.             // UDP hole punching
  276.             stP2PMessage message;
  277.             message.iMessageType = P2PTRASH;
  278.             sendto(PrimaryUDP, (const char *)&message, sizeof(message), 0,
  279.                     (const sockaddr*)&remote, sizeof(remote));
  280.                 
  281.             break;
  282.         }
  283.         case P2PMESSAGEACK:
  284.         {
  285.             // 發送消息的應答
  286.             RecvedACK = true;
  287.             break;
  288.         }
  289.         case P2PTRASH:
  290.         {
  291.             // 對方發送的打洞消息,忽略掉。
  292.             //do nothing ...
  293.             printf("Recv p2ptrash data/n");
  294.             break;
  295.         }
  296.         case GETALLUSER:
  297.         {
  298.             int usercount;
  299.             int fromlen = sizeof(remote);
  300.             int iread = recvfrom(PrimaryUDP, (char *)&usercount,
  301.                     sizeof(int), 0, (sockaddr *)&remote, &fromlen);
  302.             if(iread<=0)
  303.             {
  304.                 throw Exception("Login error/n");
  305.             }
  306.     
  307.             ClientList.clear();
  308.             cout<<"Have "<<usercount<<" users logined server:"<<endl;
  309.             for(int i = 0;i<usercount;i++)
  310.             {
  311.                 stUserListNode *node = new stUserListNode;
  312.                 recvfrom(PrimaryUDP, (char*)node, sizeof(stUserListNode),
  313.                         0, (sockaddr *)&remote, &fromlen) ;
  314.                 ClientList.push_back(node);
  315.                 cout<<"Username:"<<node->userName<<endl;
  316.                 in_addr tmp;
  317.                 tmp.S_un.S_addr = htonl(node->ip);
  318.                 cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
  319.                 cout<<"UserPort:"<<node->port<<endl;
  320.                 cout<<""<<endl;
  321.             }
  322.             break;
  323.         }
  324.         } //end switch
  325.     } //end for
  326. }
  327. int main(int argc, char* argv[])
  328. {
  329.     try
  330.     {
  331.         InitWinSock();
  332.   
  333.         PrimaryUDP = mksock(SOCK_DGRAM);
  334.         BindSock(PrimaryUDP);
  335.         cout<<"Please input server ip:";
  336.         cin>>ServerIP;
  337.         cout<<"Please input your name:";
  338.         cin>>UserName;
  339.         ConnectToServer(PrimaryUDP, UserName, ServerIP);
  340.         HANDLE threadhandle = CreateThread(NULL, 0, RecvThreadProc, NULL, NULL, NULL);
  341.         CloseHandle(threadhandle);
  342.         OutputUsage();
  343.         for(; ;)
  344.         {
  345.             char Command[COMMANDMAXC];
  346.             gets(Command);
  347.             ParseCommand(Command);
  348.         }
  349.     }
  350.     catch(Exception &e)
  351.     {
  352.         printf(e.GetMessage());
  353.         return 1;
  354.     }
  355.     return 0;
  356. }

 

  1. // 異常類
  2. // 文件名:Exception.h
  3. #ifndef __HZH_Exception__
  4. #define __HZH_Exception__
  5. #define EXCEPTION_MESSAGE_MAXLEN 256
  6. #include "string.h"
  7. class Exception
  8. {
  9. private:
  10.     char m_ExceptionMessage[EXCEPTION_MESSAGE_MAXLEN] ;
  11. public:
  12.     Exception(char *msg)
  13.     {
  14.         strncpy(m_ExceptionMessage, msg, EXCEPTION_MESSAGE_MAXLEN) ;
  15.     }
  16.     char *GetMessage()
  17.     {
  18.         return m_ExceptionMessage;
  19.     }
  20. };
  21. #endif

 

  1. // proto.h
  2. // P2P 程序傳輸協議 
  3. // 日期:2004-5-21
  4. // 作者:shootingstars([email protected])
  5. #pragma once
  6. #include <list>
  7. // 定義iMessageType的值
  8. #define LOGIN 1
  9. #define LOGOUT 2
  10. #define P2PTRANS 3
  11. #define GETALLUSER  4
  12. // 服務器端口
  13. #define SERVER_PORT 2280
  14. // Client登錄時向服務器發送的消息
  15. struct stLoginMessage
  16. {
  17.     char userName[10];
  18.     char password[10];
  19. } ;
  20. // Client註銷時發送的消息
  21. struct stLogoutMessage
  22. {
  23.     char userName[10];
  24. };
  25. // Client向服務器請求另外一個Client(userName)向自己方向發送UDP打洞消息
  26. struct stP2PTranslate
  27. {
  28.     char userName[10];
  29. };
  30. // Client向服務器發送的消息格式
  31. struct stMessage
  32. {
  33.     int iMessageType;
  34.     union _message
  35.     {
  36.         stLoginMessage loginmember;
  37.         stLogoutMessage logoutmember;
  38.         stP2PTranslate translatemessage;
  39.     }message ;
  40. };
  41. // 客戶節點信息
  42. struct stUserListNode
  43. {
  44.     char userName[10];
  45.     unsigned int ip;
  46.     unsigned short port;
  47. };
  48. // Server向Client發送的消息
  49. struct stServerToClient
  50. {
  51.     int iMessageType;
  52.     union _message
  53.     {
  54.         stUserListNode user ;
  55.     }message;
  56. };
  57. //======================================
  58. // 下面的協議用於客戶端之間的通信
  59. //======================================
  60. #define P2PMESSAGE 100               // 發送消息
  61. #define P2PMESSAGEACK 101            // 收到消息的應答
  62. #define P2PSOMEONEWANTTOCALLYOU 102  // 服務器向客戶端發送的消息
  63.                                      // 希望此客戶端發送一個UDP打洞包
  64. #define P2PTRASH        103          // 客戶端發送的打洞包,接收端應該忽略此消息
  65. // 客戶端之間發送消息格式
  66. struct stP2PMessage
  67. {
  68.     int iMessageType;
  69.     int iStringLen;         // or IP address
  70.     unsigned short Port; 
  71. };
  72. using namespace std;
  73. typedef list<stUserListNode *> UserList;
發佈了22 篇原創文章 · 獲贊 2 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章