C++ 开发P2P及时消息发送程序(2)

来源:互联网 发布:蜗牛seo 编辑:程序博客网 时间:2024/05/16 07:13

2009-04-11

徐龙

公司上sap后,一直很忙碌,没什和时间继续写....

这次先把写好的 p2p 网络库贴上来,没有完全测试,还有很多细节要完善.

Protocol.h

-----------------------------------------------------------------

#pragma once

#if !defined(PROTOCOL_H)

#define PROTOCOL_H

 

#include <list>

#include <map>

#include <queue>

#include <string>

#include <sstream>

 

using namespace std;

 

#define SRV_PORT       9000               // server listen port

#define SEND_MAX_SIZE   (1024*4)            // max size of a packet

 

#define UWAIT_TIMEOUT    50               // define how many ms to wait and else is timeout

#define WAIT_TIMES    3              // if timeout resend  3 times , else tell application error.

 

typedef   char   BUFFER[SEND_MAX_SIZE];

 

const char ProtocolFlag[] = {'L','X',0x16,0x11,0x20,0x8};

const DWORD Version = 101;

 

 

string IntToStr(int in )

{

     ostringstream os;

     os << in;

     return os.str();

}

 

void Sockaddr_inToStr(sockaddr_in *saddr,string& str)

{

     ostringstream os;

    

     os << saddr->sin_addr.S_un.S_addr << saddr->sin_port;

     str=os.str();

 

}

 

typedef struct userinfor

{

     WCHAR szUserID[255];

     DWORD dwIP;

     DWORD dwPort;

 

}USER_INFOR;

 

typedef std::list<USER_INFOR *> UserList;

 

//define socket type

typedef enum socket_type

{

     stClient = 1, // only peer client.

     stServer = 2, // only accept client to regsite and connect other client through the server.

     stBoth   = 3, // as client and as server.

}SOCKET_TYPE;

 

 

// define packet type

typedef enum packet_type

{

     ptEMPTY=1,

     ptKEEPLINE = 10,

 

 

 

     //connected peers new link

     //ptP2P_NEW_LNK_REQ=3,//request side send request msg to other peer .  A:0 -- > B:0

     //ptP2P_NEW_LNK_WAT=5,//be requested side new socket and send the packet ,wait requestSide to connect. B:1 --> A:0

     //ptP2P_NEW_LNK_FIN=7,//request side new socket and send the packet ,success to new link   A:1 --> B:1

 

 

     //peer host socket connect to other peer

 

     //cmd other peer connect to me

     ptP2S_CONN_REQ=21,// a peer's mainsocket send the packet to server's mainsocket  A:0 --> S:0

     ptS2P_CONN_CMD=22,// server's mainsocket receive ptP2S_CONN_REQ pakket then send ptS2P_CONN_CMD packet to  target peer's mainsocket  S:0 --> B:0

                      //

 

     //connect to other peer

     ptP2P_CONN_REQ=23,//a peer receive ptS2P_CONN_CMD or Appliction Call ConnectToPeer then the  peer create new socket and  new socket send the packet to  other peer's mainsocket.. B:1 --> A:0

     ptP2P_CONN_FIN=24,//a peer revcive ptP2P_CONN_REQ then create a new socket and send to other peer's socket ask the "A",success to connect.  A:1 --> B:1

 

 

     ptP2S_MSG=30,

     ptS2P_MSG=31

 

    

 

} PACKET_TYPE;

 

 

typedef struct packet_header

{

     packet_header():ePacketType(ptEMPTY),dwPacketSize(0),dwVersion(Version)

     {

         memcpy(aProtocolflag,ProtocolFlag,sizeof(ProtocolFlag));

         dwPacketSize = sizeof(packet_header);

     }

     CHAR          aProtocolflag[sizeof(ProtocolFlag)];

     DWORD              dwVersion;

     PACKET_TYPE        ePacketType;          //pakcet type

     DWORD              dwPacketSize;         // packet size , head size plus data size . is packet total size .

     DWORD              dwFromIp;            // From Ip address

     DWORD              dwFromPort;           // From server port

     DWORD              dwSeqNumber;         // sender create a id

     DWORD              dwAckNumber;         // ask the sender's id

 

     //.....body data....pay attention: dwPacketSize - sizeof(PACKET_HEADER) is data size,and dwPacketSize is the data offset address

 

}PACKET_HEADER;

 

 

typedef struct P2S_CONN_REQ_PKT:packet_header // a peer send to server

{

     DWORD dwConnToPeerIP;

     DWORD dwConnToPort;

 

}P2S_CONN_REQ_PKT;

 

typedef struct S2P_CONN_CMD_PKT:packet_header // server send to a peer

{

 

 

     DWORD dwReqPeerIP;

     DWORD dwReqPeerPort;

 

 

}S2P_CONN_CMD_PKT;

 

#define MaxDataSize SEND_MAX_SIZE-sizeof(PACKET_HEADER);

#endif

 

 

---------------------------------------------------------------------------------

Udbsocket.h

---------------------------------------------------------------------------------

#pragma once

#include "Protocol.h"

#include "wsainitializer.h"

#include "Thread.h"

#include <stdlib.h>

class TUdpSocket;

typedef void (*tOnSending)(TUdpSocket *pUdpSocket,sockaddr *pToAddr,char* szBuff,const int BuffLen);

typedef void (*tOnReceiving)(TUdpSocket *pUdpSocket,char* szBuff,const int BuffLen);

typedef void (*tOnDisconnected)(TUdpSocket *pUdpSocket);

 

class TUdpSocket

{

public:

     TUdpSocket(void);

     ~TUdpSocket(void);

 

     TUdpSocket& operator=(const TUdpSocket& ) { return *this; }

 

 

     bool Create(void);

     bool Bind(int port);

 

     int  SendTo(const int dwIP,const int dwPort,const char* szBuff,const int BuffLen);

     int  SendTo(const char* szIP,const int dwPort,const char* szBuff,const int BuffLen);

 

     int  Send(const char* szBuff,const int BuffLen);

 

     void Listen(void);

     void Connect(void);

     //property

     tOnSending OnSending;

     tOnReceiving OnReceiving;

     tOnDisconnected OnDisconnected;

 

     int ServerIp;

     int ServerPort;

 

     bool Connected;

private:

     SOCKET m_Socket;

     TThread *m_thread;

     bool m_binded;

     DWORD   m_lastSndTime;

     DWORD   m_lastKeepTime;

     DWORD   m_waitTimes;

     static void ReceiveData(LPVOID Parent);

};

 

--------------------------------------

Peersocket.h

--------------------------------------

#pragma once

#include "UdpSocket.h"

 

////class TUdpSocketKey

////{

////public:

//// TUdpSocketKey();

//// TUdpSocketKey(DWORD ip,DWORD port):m_ip(ip),m_port(port){};

//// TUdpSocketKey(sockaddr_in &ad):m_ip(ad.sin_addr.s_addr),m_port(ad.sin_port){};

//// ~TUdpSocketKey(void);

////

//// bool operator == (const TUdpSocketKey& y ) { return (m_ip == y.m_ip && m_port == y.m_port);};

//// bool operator != (const TUdpSocketKey& y ) { return !(m_ip == y.m_ip && m_port == y.m_port); };

//// bool operator <  (const TUdpSocketKey& y ) { return ((m_ip < y.m_ip) || ((m_ip == y.m_ip) && (m_port < y.m_port))); };

//// bool operator >  (const TUdpSocketKey& y ) { return ((m_ip > y.m_ip) || ((m_ip == y.m_ip) && (m_port > y.m_port))); };

//// bool operator <= (const TUdpSocketKey& y ) { return ((m_ip < y.m_ip) || ((m_ip == y.m_ip) && (m_port <= y.m_port))); };

//// bool operator >= (const TUdpSocketKey& y ) { return ((m_ip > y.m_ip) || ((m_ip == y.m_ip) && (m_port >= y.m_port))); };

////

////

////

////private:

//// DWORD m_ip;

//// DWORD m_port;

////};

 

 

 

typedef std::map<string,TUdpSocket*> TUdpSocketMap;

 

class TPeerSocket :

     public TUdpSocket

{

 

public:

     TPeerSocket(void);

     ~TPeerSocket(void);

 

     void ConnecdToPeer(DWORD dwIP,DWORD dwPort); // to do create new socket and new socket send ptP2P_CONN_REQ

     void RequestPeerToMe(DWORD dwIP,DWORD dwPort); // to do main socket send ptP2S_CONN_REQ to server

 

     //property

     socket_type eSocketType;

private:

     TUdpSocketMap m_UdpSocketMap;

 

     static void Sending(TUdpSocket *pUdpSocket,sockaddr *pToAddr,char* szBuff,const int BuffLen);

     static void Receiving(TUdpSocket *pUdpSocket,char* szBuff,const int BuffLen);

 

};

 

;

 

 

-------------------------------------------------------------------------------------------------------------

Udpsocket.cpp

----------------------------------------------------------------------------------------------------------------------------

 

#include "StdAfx.h"

#include "UDPSocket.h"

//#include <iostream>

 

 

void TUdpSocket::ReceiveData(LPVOID Parent)

{

     TUdpSocket* pudp=((TUdpSocket*)Parent);

 

     BUFFER buf;

     struct sockaddr_in recAddr;

     int sockaddrLen=sizeof(sockaddr_in);

     ZeroMemory(&buf,sizeof(buf));

     int recSize=recvfrom(pudp->m_Socket,buf,SEND_MAX_SIZE,0,(struct sockaddr *)&recAddr,&sockaddrLen);

     if (recSize>0)

     {

 

         if (recSize > sizeof(PACKET_HEADER))

         {

              int ip=ntohl(recAddr.sin_addr.s_addr);

              int port = ntohs(recAddr.sin_port);

              PACKET_HEADER *pPacketHeader = (PACKET_HEADER*)&buf;

 

              pPacketHeader->dwFromIp = ip;

              pPacketHeader->dwFromPort = port;

              if(pudp->ServerIp != 0) // as a client

              {

                   if(pudp->ServerIp ==ip && pudp->ServerPort==port && pPacketHeader->ePacketType==ptKEEPLINE)

                   {

                      

                       pudp->m_lastKeepTime=::GetTickCount();  // record last recevied the ptkeeline packet time

                       pudp->Connected = true;

                       pudp->m_waitTimes = 0;

                      

                   }

             

 

                   DWORD dwCT = ::GetTickCount();

                   if ((dwCT - pudp->m_lastKeepTime) > UWAIT_TIMEOUT)  //time out

                   {

                       pudp->m_waitTimes++;

                       pudp->m_lastKeepTime=::GetTickCount();

                       if (pudp->m_waitTimes>WAIT_TIMES) // out the max times

                       {

                            pudp->Connected=false;

                            pudp->m_thread->Stop();

                            if (pudp->OnDisconnected!=NULL)

                            {

                                 pudp->OnDisconnected(pudp);

                            }

                       }

                   }

              }

         }

         if ( pudp->OnReceiving != NULL)

         {

                   pudp->OnReceiving(pudp,(char*)&buf,recSize);

 

         }

         if(pudp->ServerIp != 0 && (::GetTickCount()-pudp->m_lastSndTime ) / 2 > UWAIT_TIMEOUT ) // as a client // snd keep line pkt

         {

              PACKET_HEADER sndPkt ;

              sndPkt.ePacketType=ptKEEPLINE;

              pudp->Send((const char*)&sndPkt,sizeof(sndPkt));

              pudp->m_lastSndTime = ::GetTickCount();

         }

     }

}

 

TUdpSocket::TUdpSocket(void):m_Socket(INVALID_SOCKET),m_thread(NULL),m_binded(false),ServerIp(0),ServerPort(0)

{

     m_thread = new TThread(this);

     m_thread->OnExecute = ReceiveData;  

}

 

TUdpSocket::~TUdpSocket()

{

     if (m_Socket!=INVALID_SOCKET)

     {

         closesocket(m_Socket);

     }

     if (m_thread != NULL)

     {

         delete(m_thread);

     }

}

 

void TUdpSocket::Listen()

{

     if(m_binded && OnReceiving != NULL)

     {

         m_lastKeepTime=::GetTickCount();

         m_thread->Start();

     }

}

 

 

void TUdpSocket::Connect()

{

     if(OnReceiving != NULL)

     {

         m_lastKeepTime=::GetTickCount();

         m_thread->Start();

     }

}

 

 

//绑定端口

bool TUdpSocket::Bind(int Port)

{

     m_binded = false;

     m_thread->Stop();

     if (m_Socket!=INVALID_SOCKET)

     {

         int ret=0;

         SOCKADDR_IN addr;

         ZeroMemory(&addr,sizeof(addr));

         addr.sin_family = AF_INET;

         addr.sin_addr.s_addr = INADDR_ANY;

         addr.sin_port = htons(Port);

 

         ret = bind(m_Socket,(struct sockaddr *)&addr,sizeof(addr));

         if(ret!=0)

         {

              closesocket(m_Socket);

              m_binded = false;

         }

         else

         {

              m_binded = true;

         }

     }

    

     return m_binded;

}

 

 

//创建UDP套接字,并设置可重绑定

bool TUdpSocket::Create()

{

     bool flag = true;

     int ret=0;

     m_Socket = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);

     if(m_Socket==INVALID_SOCKET)

     {

         return false;

     }

 

     //设置套接字可重绑定(新实例会替掉旧实例)

     ret = setsockopt(m_Socket,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag));

     if(ret!=0)

     {

         closesocket(m_Socket);

         return false;

     }

 

    

     return true;

}

 

 

 

int TUdpSocket::SendTo(const int dwIP, const int dwPort, const char *szBuff, const int BuffLen)

{   

     int ret = 0;

     if(m_binded)

     {

         BUFFER buf;

         SOCKADDR_IN addr;

         ZeroMemory(&buf,sizeof(buf));

         ZeroMemory(&addr,sizeof(addr));

         memcpy(&buf,szBuff,BuffLen);

        

         addr.sin_family = AF_INET; 

         addr.sin_addr.s_addr = htons(dwIP);

         addr.sin_port = htons(dwPort);

 

         if ( OnSending != NULL)

         {

              OnSending(this,(sockaddr *)&addr,(char*)&buf,BuffLen);

         }

        

         ret= sendto(m_Socket,(char*)&buf,BuffLen,0,(sockaddr *)&addr,sizeof(addr));

     }

     return ret;

}

 

 

int TUdpSocket::SendTo(const char *szIP, const int dwPort, const char *szBuff, const int BuffLen)

{

     int ret=0;

     if(m_binded)

     {

         BUFFER buf;                

         SOCKADDR_IN addr;

 

         ZeroMemory(&buf,sizeof(buf));

         ZeroMemory(&addr,sizeof(addr));

        

         memcpy(&buf,szBuff,BuffLen);

 

         addr.sin_family = AF_INET;

         addr.sin_addr.s_addr = inet_addr(szIP);

         addr.sin_port = htons(dwPort);

 

         if ( OnSending != NULL)

         {

              OnSending(this,(sockaddr *)&addr,(char*)&buf,BuffLen);

         }       

         ret= sendto(m_Socket,(char*)&buf,BuffLen,0,(sockaddr *)&addr,sizeof(addr));

     }

     return ret;

 

}

 

int TUdpSocket::Send(const char *szBuff, const int BuffLen)

{   

     if (ServerIp != 0 && ServerPort != 0 )

     {

         return SendTo(ServerIp, ServerPort, szBuff, BuffLen);

     }

     return 0;

}

 

------------------------------------------------

Peersocket.cpp

--------------------------------------------

#include "StdAfx.h"

#include "PeerSocket.h"

 

 

 

void TPeerSocket::ConnecdToPeer(DWORD dwIP,DWORD dwPort) // to do create new socket and new socket send ptP2P_CONN_REQ

{

     BUFFER sndBuf;

     string key = IntToStr(dwIP) + IntToStr(dwPort);

     TUdpSocket* pUdsItem = new TUdpSocket();

 

     this->m_UdpSocketMap.insert(make_pair(key,pUdsItem));

     pUdsItem->ServerIp=dwIP;

     pUdsItem->ServerPort=dwPort;                  

     pUdsItem->Connect();

 

     ZeroMemory(&sndBuf,sizeof(sndBuf));

     ((PACKET_HEADER*)&sndBuf)->ePacketType = ptP2P_CONN_REQ;

     memcpy(((PACKET_HEADER*)&sndBuf)->aProtocolflag,ProtocolFlag,sizeof(ProtocolFlag));

     ((PACKET_HEADER*)&sndBuf)->dwPacketSize = sizeof(PACKET_HEADER);

     pUdsItem->Send((const char*)&sndBuf,sizeof(PACKET_HEADER));

}

 

void TPeerSocket::RequestPeerToMe(DWORD dwIP,DWORD dwPort) // to do main socket send ptP2S_CONN_REQ to server

{

     BUFFER sndBuf;

 

     ZeroMemory(&sndBuf,sizeof(sndBuf));

     ((P2S_CONN_REQ_PKT*)&sndBuf)->ePacketType = ptP2S_CONN_REQ;

     memcpy(((P2S_CONN_REQ_PKT*)&sndBuf)->aProtocolflag,ProtocolFlag,sizeof(ProtocolFlag));

     ((P2S_CONN_REQ_PKT*)&sndBuf)->dwPacketSize = sizeof(P2S_CONN_REQ_PKT);

     ((P2S_CONN_REQ_PKT*)&sndBuf)->dwConnToPeerIP=dwIP;

     ((P2S_CONN_REQ_PKT*)&sndBuf)->dwConnToPort=dwPort;

     this->Send((const char*)&sndBuf,sizeof(P2S_CONN_REQ_PKT));

 

}

 

void TPeerSocket::Sending(TUdpSocket *pUdpSocket,sockaddr *pToAddr,char* szBuff,const int BuffLen)

{

    

}

void TPeerSocket::Receiving(TUdpSocket *pUdpSocket,char* szBuff,const int BuffLen)

{

 

     if ( BuffLen<sizeof(PACKET_HEADER) ) return ;

 

     string key;

     TUdpSocket *pUdsItem;

     BUFFER sndBuf;

 

     PACKET_HEADER *pPacketHeader = (PACKET_HEADER*)szBuff;

     TPeerSocket *pPeerSocket = (TPeerSocket*)pUdpSocket;

 

     //Server socket message Process procedure

     if ((pPeerSocket->eSocketType & stServer) ==  stServer)

     {

         switch ( pPacketHeader->ePacketType )

         {

              case ptP2S_CONN_REQ: // a peer called RequestPeerToMe active the msg ,server receive conn_req pakket then send the ptS2P_CONN_CMD packet to  target peer ( b),cmd the b connect to a . S:0 --> B:0

 

                  

                   //to do  send ptS2P_CONN_CMD to target peer

 

                   ZeroMemory(&sndBuf,sizeof(sndBuf));

                   ((S2P_CONN_CMD_PKT*)&sndBuf)->ePacketType = ptS2P_CONN_CMD;

                   ((S2P_CONN_CMD_PKT*)&sndBuf)->dwReqPeerIP = pPacketHeader->dwFromIp;

                   ((S2P_CONN_CMD_PKT*)&sndBuf)->dwReqPeerPort = pPacketHeader->dwFromPort;

                   memcpy(((S2P_CONN_CMD_PKT*)&sndBuf)->aProtocolflag,ProtocolFlag,sizeof(ProtocolFlag));

                   ((S2P_CONN_CMD_PKT*)&sndBuf)->dwPacketSize = sizeof(S2P_CONN_CMD_PKT);

 

 

                   pPeerSocket->SendTo(((P2S_CONN_REQ_PKT*)pPacketHeader)->dwConnToPeerIP,((P2S_CONN_REQ_PKT*)pPacketHeader)->dwConnToPort,(const char*)&sndBuf,sizeof(PACKET_HEADER));

 

                   break;

 

              case ptP2S_MSG:

 

                   break;

 

         }

     }

    

     // client socket message process procedure

     if ((pPeerSocket->eSocketType & stClient) == stClient)

     {

         switch (  pPacketHeader->ePacketType )

         {

 

              case ptS2P_CONN_CMD:

                   //the  server's packet

                   if (pPacketHeader->dwFromIp == pPeerSocket->ServerIp && pPacketHeader->dwFromPort == pPeerSocket->ServerPort)

                   {

                  

                        pPeerSocket->ConnecdToPeer(((S2P_CONN_CMD_PKT*)pPacketHeader)->dwReqPeerIP,((S2P_CONN_CMD_PKT*)pPacketHeader)->dwFromPort);

 

 

                   }

                   break;

 

              case ptP2P_CONN_REQ: // a peer calld ConnecdToPeer active the msg

 

                   key = IntToStr(pPacketHeader->dwFromIp) + IntToStr(pPacketHeader->dwFromPort);

                   pUdsItem = new TUdpSocket();

 

                   pPeerSocket->m_UdpSocketMap.insert(make_pair(key,pUdsItem)); // add a peer process socket

                   pUdsItem->ServerIp=pPacketHeader->dwFromIp;

                   pUdsItem->ServerPort=pPacketHeader->dwFromPort;                 

                   pUdsItem->Connect();

 

                   ZeroMemory(&sndBuf,sizeof(sndBuf));

                   ((PACKET_HEADER*)&sndBuf)->ePacketType = ptP2P_CONN_FIN;

                   memcpy(((PACKET_HEADER*)&sndBuf)->aProtocolflag,ProtocolFlag,sizeof(ProtocolFlag));

                   ((PACKET_HEADER*)&sndBuf)->dwPacketSize = sizeof(PACKET_HEADER);

                   pUdsItem->Send((const char*)&sndBuf,sizeof(PACKET_HEADER));

                  

 

                   break;

 

 

              case ptS2P_MSG:

                   //the own server's packet

                   if (pPacketHeader->dwFromIp == pPeerSocket->ServerIp && pPacketHeader->dwFromPort == pPeerSocket->ServerPort)

                   {

                   }

 

                   break;

 

         }

     }

 

 

}

 

TPeerSocket::TPeerSocket(void)

{

     OnSending=Sending;

     OnReceiving=Receiving;

}

 

TPeerSocket::~TPeerSocket(void)

{

}

 

 

 

 

 

 

原创粉丝点击