当前位置: 首页 > news >正文

郑州网站建设哪家专业浙江大经建设集团网站

郑州网站建设哪家专业,浙江大经建设集团网站,西安团购网站建设,北京的互联网公司有哪些论坛上经常有对P2P原理的讨论#xff0c;但是讨论归讨论#xff0c;很少有实质的东西产生#xff08;源代码#xff09;。呵呵#xff0c;在这里我就用自己实现的一个源代码来说明UDP穿越NAT的原理。 首先先介绍一些基本概念#xff1a; NAT(Network Address Transla…  论坛上经常有对P2P原理的讨论但是讨论归讨论很少有实质的东西产生源代码。呵呵在这里我就用自己实现的一个源代码来说明UDP穿越NAT的原理。 首先先介绍一些基本概念     NAT(Network Address Translators)网络地址转换网络地址转换是在IP地址日益缺乏的情况下产生的它的主要目的就是为了能够地址重用。NAT分为两大类基本的NAT和NAPT(Network Address/Port Translator)。     最开始NAT是运行在路由器上的一个功能模块。         最先提出的是基本的NAT它的产生基于如下事实一个私有网络域中的节点中只有很少的节点需要与外网连接呵呵这是在上世纪90年代中期提出的。那么这个子网中其实只有少数的节点需要全球唯一的IP地址其他的节点的IP地址应该是可以重用的。     因此基本的NAT实现的功能很简单在子网内使用一个保留的IP子网段这些IP对外是不可见的。子网内只有少数一些IP地址可以对应到真正全球唯一的IP地址。如果这些节点需要访问外部网络那么基本NAT就负责将这个节点的子网内IP转化为一个全球唯一的IP然后发送出去。(基本的NAT会改变IP包中的原IP地址但是不会改变IP包中的端口)     关于基本的NAT可以参看RFC 1631         另外一种NAT叫做NAPT从名称上我们也可以看得出NAPT不但会改变经过这个NAT设备的IP数据报的IP地址还会改变IP数据报的TCP/UDP端口。基本NAT的设备可能我们见的不多呵呵我没有见到过NAPT才是我们真正讨论的主角。看下图                                 Server S1                                                  18.181.0.31:1235                                                                |           ^  Session 1 (A-S1)  ^      |            |  18.181.0.31:1235  |      |             v 155.99.25.11:62000 v      |                                          |                                      NAT                                  155.99.25.11                                       |           ^  Session 1 (A-S1)  ^      |            |  18.181.0.31:1235  |      |            v   10.0.0.1:1234    v      |                                        |                                    Client A                                 10.0.0.1:1234     有一个私有网络10.*.*.*Client A是其中的一台计算机这个网络的网关一个NAT设备的外网IP是155.99.25.11(应该还有一个内网的IP地址比如10.0.0.10)。如果Client A中的某个进程这个进程创建了一个UDP Socket,这个Socket绑定1234端口想访问外网主机18.181.0.31的1235端口那么当数据包通过NAT时会发生什么事情呢     首先NAT会改变这个数据包的原IP地址改为155.99.25.11。接着NAT会为这个传输创建一个SessionSession是一个抽象的概念如果是TCP也许Session是由一个SYN包开始以一个FIN包结束。而UDP呢以这个IP的这个端口的第一个UDP开始结束呢呵呵也许是几分钟也许是几小时这要看具体的实现了并且给这个Session分配一个端口比如62000然后改变这个数据包的源端口为62000。所以本来是10.0.0.1:1234-18.181.0.31:1235的数据包到了互联网上变为了155.99.25.11:62000-18.181.0.31:1235。     一旦NAT创建了一个Session后NAT会记住62000端口对应的是10.0.0.1的1234端口以后从18.181.0.31发送到62000端口的数据会被NAT自动的转发到10.0.0.1上。注意这里是说18.181.0.31发送到62000端口的数据会被转发其他的IP发送到这个端口的数据将被NAT抛弃这样Client A就与Server S1建立以了一个连接。     呵呵上面的基础知识可能很多人都知道了那么下面是关键的部分了。     看看下面的情况     Server S1                                     Server S2  18.181.0.31:1235                              138.76.29.7:1235         |                                             |         |                                             |         --------------------------------------------                                |    ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^    |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |    v 155.99.25.11:62000 v      |      v 155.99.25.11:62000 v                                |                             Cone NAT                           155.99.25.11                                |    ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^    |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |    v   10.0.0.1:1234    v      |      v   10.0.0.1:1234    v                                |                             Client A                          10.0.0.1:1234     接上面的例子如果Client A的原来那个Socket(绑定了1234端口的那个UDP Socket)又接着向另外一个Server S2发送了一个UDP包那么这个UDP包在通过NAT时会怎么样呢     这时可能会有两种情况发生一种是NAT再次创建一个Session并且再次为这个Session分配一个端口号比如62001。另外一种是NAT再次创建一个Session但是不会新分配一个端口号而是用原来分配的端口号62000。前一种NAT叫做Symmetric NAT后一种叫做Cone NAT。我们期望我们的NAT是第二种呵呵如果你的NAT刚好是第一种那么很可能会有很多P2P软件失灵。可以庆幸的是现在绝大多数的NAT属于后者即Cone NAT        好了我们看到通过NAT,子网内的计算机向外连结是很容易的NAT相当于透明的子网内的和外网的计算机不用知道NAT的情况。     但是如果外部的计算机想访问子网内的计算机就比较困难了而这正是P2P所需要的。     那么我们如果想从外部发送一个数据报给内网的计算机有什么办法呢首先我们必须在内网的NAT上打上一个“洞”也就是前面我们说的在NAT上建立一个Session这个洞不能由外部来打只能由内网内的主机来打。而且这个洞是有方向的比如从内部某台主机比如192.168.0.10向外部的某个IP(比如219.237.60.1)发送一个UDP包那么就在这个内网的NAT设备上打了一个方向为219.237.60.1的“洞”这就是称为UDP Hole Punching的技术以后219.237.60.1就可以通过这个洞与内网的192.168.0.10联系了。但是其他的IP不能利用这个洞。 呵呵现在该轮到我们的正题P2P了。有了上面的理论实现两个内网的主机通讯就差最后一步了那就是鸡生蛋还是蛋生鸡的问题了两边都无法主动发出连接请求谁也不知道谁的公网地址那我们如何来打这个洞呢我们需要一个中间人来联系这两个内网主机。     现在我们来看看一个P2P软件的流程以下图为例                        Server S 219.237.60.1                           |                           |    --------------------------------------------    |                                             |  NAT A (外网IP:202.187.45.3)                 NAT B (外网IP:187.34.1.56)    |   (内网IP:192.168.0.1)                      | (内网IP:192.168.0.1)    |                                             | Client A  (192.168.0.20:4000)             Client B (192.168.0.10:40000)     首先Client A登录服务器NAT A为这次的Session分配了一个端口60000那么Server S收到的Client A的地址是202.187.45.3:60000这就是Client A的外网地址了。同样Client B登录Server SNAT B给此次Session分配的端口是40000那么Server S收到的B的地址是187.34.1.56:40000。     此时Client A与Client B都可以与Server S通信了。如果Client A此时想直接发送信息给Client B那么他可以从Server S那儿获得B的公网地址187.34.1.56:40000是不是Client A向这个地址发送信息Client B就能收到了呢答案是不行因为如果这样发送信息NAT B会将这个信息丢弃因为这样的信息是不请自来的为了安全大多数NAT都会执行丢弃动作。现在我们需要的是在NAT B上打一个方向为202.187.45.3即Client A的外网地址的洞那么Client A发送到187.34.1.56:40000的信息,Client B就能收到了。这个打洞命令由谁来发呢呵呵当然是Server S。     总结一下这个过程如果Client A想向Client B发送信息那么Client A发送命令给Server S请求Server S命令Client B向Client A方向打洞。呵呵是不是很绕口不过没关系想一想就很清楚了何况还有源代码呢侯老师说过在源代码面前没有秘密 8然后Client A就可以通过Client B的外网地址与Client B通信了。         注意以上过程只适合于Cone NAT的情况如果是Symmetric NAT那么当Client B向Client A打洞的端口已经重新分配了Client B将无法知道这个端口如果Symmetric NAT的端口是顺序分配的那么我们或许可以猜测这个端口号可是由于可能导致失败的因素太多我们不推荐这种猜测端口的方法。         下面是一个模拟P2P聊天的过程的源代码过程很简单P2PServer运行在一个拥有公网IP的计算机上P2PClient运行在两个不同的NAT后注意如果两个客户端运行在一个NAT后本程序很可能不能运行正常这取决于你的NAT是否支持loopback translation详见http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt当然此问题可以通过双方先尝试连接对方的内网IP来解决但是这个代码只是为了验证原理并没有处理这些问题后登录的计算机可以获得先登录计算机的用户名后登录的计算机通过send username message的格式来发送消息。如果发送成功说明你已取得了直接与对方连接的成功。     程序现在支持三个命令send , getu , exit         send格式send username message     功能发送信息给username         getu格式getu     功能获得当前服务器用户列表         exit格式exit     功能注销与服务器的连接服务器不会自动监测客户是否吊线             代码很短相信很容易懂如果有什么问题可以给我发邮件zhouhuis22sina.com  或者在CSDN上发送短消息。同时欢迎转发此文但希望保留作者版权8-。         最后感谢CSDN网友 PiggyXP 和 Seilfer的测试帮助 P2PServer.c /* P2P 程序服务端  *  * 文件名P2PServer.c  *  * 日期2004-5-21  *  * 作者shootingstars(zhouhuis22sina.com)  *  */ #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 UserIteratorClientList.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_familyAF_INET;   local.sin_port htons(SERVER_PORT);   local.sin_addr.s_addr htonl(INADDR_ANY);   int nResultbind(PrimaryUDP,(sockaddr*)local,sizeof(sockaddr));   if(nResultSOCKET_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 UserIteratorClientList.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 UserIteratorClientList.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_familyAF_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 UserIteratorClientList.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; } /* P2P 程序客户端  *  * 文件名P2PClient.c  *  * 日期2004-5-21  *  * 作者shootingstars(zhouhuis22sina.com)  *  */ #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    5 SOCKET 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 UserIteratorClientList.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(iread0)  {   throw Exception(Login error\n);  }  // 登录到服务端后接收服务端发来的已经登录的用户的信息  coutHave usercount users logined server:endl;  for(int i 0;iusercount;i)  {   stUserListNode *node new stUserListNode;   recvfrom(sock, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)remote, fromlen);   ClientList.push_back(node);   coutUsername:node-userNameendl;   in_addr tmp;   tmp.S_un.S_addr htonl(node-ip);   coutUserIP:inet_ntoa(tmp)endl;   coutUserPort:node-portendl;   coutendl;  } } void OutputUsage() {  coutYou 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 UserIteratorClientList.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 i0;iMAXRETRY;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 j0;j10;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(i5;;i)   {    if(CommandLine[i]! )     sendname[i-5]CommandLine[i];    else    {     sendname[i-5]\0;     break;    }   }   strcpy(message, (CommandLine[i1]));   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(iread0)   {    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(iread10)      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(iread0)     {      throw Exception(Login error\n);     }          ClientList.clear();     coutHave usercount users logined server:endl;     for(int i 0;iusercount;i)     {      stUserListNode *node new stUserListNode;      recvfrom(PrimaryUDP, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)remote, fromlen);      ClientList.push_back(node);      coutUsername:node-userNameendl;      in_addr tmp;      tmp.S_un.S_addr htonl(node-ip);      coutUserIP:inet_ntoa(tmp)endl;      coutUserPort:node-portendl;      coutendl;     }     break;    }   }  } } int main(int argc, char* argv[]) {  try  {   InitWinSock();      PrimaryUDP mksock(SOCK_DGRAM);   BindSock(PrimaryUDP);   coutPlease input server ip:;   cinServerIP;   coutPlease input your name:;   cinUserName;   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; } /* 异常类  *  * 文件名Exception.h  *  * 日期2004.5.5  *  * 作者shootingstars(zhouhuis22sina.com)  */ #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 程序传输协议  *  * 日期2004-5-21  *  * 作者shootingstars(zhouhuis22sina.com)  *  */ #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 liststUserListNode * UserList; 转载于:https://www.cnblogs.com/zjoch/archive/2008/12/26/1362666.html
http://www.sadfv.cn/news/31344/

相关文章:

  • 网络公司建设网站自己做网站发信息
  • 用自己的ip怎么查看dw8建设的网站免费网站正能量入口下载
  • 招聘网站做沙龙大田县建设资讯网站
  • 东莞做网站(信科网络)北京装饰公司名称
  • 如何用百度上传图片做网站外链wordpress 如何回到初始化
  • 网站怎么上传网站搜索引擎优化方案
  • h5建设网站小程序代理推广
  • 广州市网站建设制作费用建设城市2的游戏在哪个网站
  • 网站建设的目的与意义是什么做网站代理怎么赚钱
  • 洛阳设计网站公司手机商城下载app
  • ui设计做兼职的网站有哪些网络销售网站有哪些
  • 中小企业微信网站建设上海自建站招聘
  • 康定网站建设公司网站域名解析错误怎么解决
  • 天津网站建设行业新闻企业网站免费推广软件
  • 网站上传照片失败python 解析 wordpress
  • 男生为女生做网站建站公司网站模板
  • 中核工建设集团有限公司网站长沙网站定制建设
  • 中国知名网站排名wordpress 投票
  • 国外网站发展建设网站必须做ipv6
  • 中国风网站建设百度app手机版
  • 网站排名怎么上去公司商标设计
  • 企业门户网站系统下载一键生成广告图
  • 网站设计制作公司需要什么资质江苏省工程建设标准定额网站
  • 常州做网站麦策搭建小程序的方式有几种
  • 没有网站怎么做cpa网站建设现在还有没有市场
  • 网站制作软件下载wordpress自动视频播放
  • 网站seo专员宣传片制作公司宣传文案
  • 网站建设规划书百度文库电子商务营销推广
  • 文本文档做网站怎么加图片上海网站推广有哪些
  • 做优化网站怎么优化代码东莞找工作