Click here to Skip to main content
6,634,665 members and growing! (17,420 online)
Email Password   helpLost your password?
General Programming » Internet / Network » Peer to Peer     Intermediate

Peer2Peer socket sample

By mohamad hajibegloo

A fully error handled and easy to use peer2peer2 library.
VC6Win2K, WinXP, MFC, Dev
Posted:30 Dec 2004
Views:46,802
Bookmarked:38 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
9 votes for this article.
Popularity: 3.01 Rating: 3.16 out of 5
2 votes, 22.2%
1

2

3
3 votes, 33.3%
4
4 votes, 44.4%
5

Sample Image

Introduction

Peer-2-peer socket communication is the base part of every network application and I want to develop an easy to use and fully error handled library for it.

Using the code

For using this, you must do the following steps:

  1. Make an instance of CP2PConnection class:
    CP2PConnection p2p;
  2. Create a static function in your class with this prototype:
    static void CALLBACK NotifyProc(LPVOID lpParam, CString LogMsg, 
                                     CString LogMsgDes, UINT nCode); 

    Call this function when any error or event occurs. When an error or event occurs, call this function with ncode == 0, and when you receive a message from peer application library, call this function with ncode == 1.

  3. Initialize library on constructor by:
    p2p(NotifyProc,this)
  4. Call connect() or bind() to create connection.

How the library works

This library consists of four classes (CBuffer, CLock, CP2PConnection, CListenSocket). CBuffer is a class that works as storage; you can read and write some data into this buffer without worrying about memory management. CLock is a wrapper class for CRITICAL_SECTION. The main classes of the library are CP2PConnection, CListenSocket.

CListenSocket is a listener thread that listens at a port and accepts new connection. Because our program is p2p, we can accept just one connection, and accepting new connection causes closing the old connection if it exists.

CP2PConnection keeps connection state and changes the connection state when different events or errors occur for socket. The errors and events that may occur for Connect are:

    #define NETEVENT_ERROR 100  //network error

    #define READ_ERROR 101 //read error

    #define CONNECT_ERROR 102 //connection failed

    #define CLOSE_ERROR 103 //connection closed

    #define WRITE_ERROR 104 //write error

    #define CONNON_ERROR 105 //socket error

    #define CONNECT_EVENT 0  // connecting event

    #define ACCEPT_EVENT 1    //accepting event

    #define CLOSE_EVENT 2    //normal closing socket event

I use these events and errors and change state according to them.

void CP2PConnection::StateChange(int NewCondition,char * log)
{
    CLock cs(m_statecs, "CP2PConnection::StateChange" );

    if(log) ReportError(log);

    switch(m_state)
    {
        ////////////////////////////////////////////////////////////////

    case not_connect:  //in this state key is off and mouse isn't over the key

        {
            switch(NewCondition)
            {
            case CONNECT_EVENT:
                {
                    m_Active_Sock=m_Connect_Sock;
                    m_state=estab_connect;
                    InitSocketThread();
                }
                break;
            case ACCEPT_EVENT:
                {
                    m_Active_Sock=m_ClistenSock.clientSocket;
                    m_state=estab_accept;
                    InitSocketThread();
                }
                break;
            default:
                m_Active_Sock=NULL;
                break;
            }
        }
        break;
        //////////////////////////////////////////////////////////////////

    case estab_connect:
        {
            switch(NewCondition)
            {
            case CONNECT_EVENT:
                break;
            case ACCEPT_EVENT:
                {
                    stop();
                    m_Active_Sock=m_ClistenSock.clientSocket;
                    m_state=estab_accept;
                    InitSocketThread();
                }
                break;
            case NETEVENT_ERROR:
            case READ_ERROR:
            case CONNECT_ERROR:
            case CLOSE_ERROR:
            case CLOSE_EVENT:
            case WRITE_ERROR:

                {
                    stop();
                    m_state=not_connect;
                    m_Active_Sock=NULL;
                }
                break;
            }
        }
        break;
        //////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////

    case estab_accept:
        {
            switch(NewCondition)
            {
            case CONNECT_EVENT:
                {
                    stop();
                    m_Active_Sock=m_Connect_Sock;
                    m_state=estab_connect;
                    InitSocketThread();
                }
                break;
            case ACCEPT_EVENT:
                {
                    stop();
                    m_Active_Sock=m_ClistenSock.clientSocket;
                    m_state=estab_accept;
                    InitSocketThread();
                }
                break;
            case NETEVENT_ERROR:
            case READ_ERROR:
            case CONNECT_ERROR:
            case CLOSE_ERROR:
            case CLOSE_EVENT:
            case WRITE_ERROR:
            case CONNON_ERROR:
            //case default:

                {
                    stop();
                    m_state=not_connect;
                    m_Active_Sock=NULL;
                }
                break;
            }
        }
        break;
        //////////////////////////////////////////////////////////////////

    }

}

I use a simple format for messages, that is:

messagelen(int),message body

As I explained in my previous article, receiver must take care about messages that it receives form the network because some messages may be split into two or more network packets. So I use an intermediate buffer and store all arrived messages at that buffer. This buffer then evaluates packets and extract messages from it.

bool CP2PConnection::OnRead()
{
//    CLock cs(m_statecs, "CP2PConnection::OnRead" );

    DWORD dwSize = 0;
    int nRet = ioctlsocket(m_Active_Sock, FIONREAD, &dwSize);
    if (nRet == -1)
        return true;

    if (dwSize == 0)
        return false;


    BYTE* pData = new BYTE[dwSize+1];

    int nRead = recv(m_Active_Sock, (char*) pData, dwSize, 0);
    if (nRead == -1)
        return true;


    m_recvBuff.Write(pData, nRead);
    delete [] pData;

    while (m_recvBuff.GetBufferLen() > (sizeof(int)*1))
    {
        int nSize = 0;
        int nCommand = 0;
        int nPageId = 0;
        CopyMemory(&nSize, m_recvBuff.GetBuffer(), sizeof(int));


        if (nSize && m_recvBuff.GetBufferLen() >= (UINT) nSize)
        {
            // Read off header

            m_recvBuff.Read((PBYTE) &nSize, sizeof(int));

        ////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////

            // SO you would process your data here

            //

            // I'm just going to post message so we can see the data

        //    nSize -= sizeof(int);


            int nTrueSize = nSize+1;
            PBYTE pData = new BYTE[nTrueSize];

            CString str;

            m_recvBuff.Read(pData,nSize);
            pData[nTrueSize-1] =  NULL;
            str = pData;
            //::PostMessage(m_hWnd, WM_REC_MSG, 0, (LPARAM) AllocBuffer(str));

        //    AfxGetApp()->GetMainWnd()->SetWindowText(str);

            m_pNotifyProc(m_pNotifyProcCalss,str,(CString)"",1 );
    //        Sleep(1000);

            //((CScoketApp *)AfxGetApp())->DataReceived(str);


            // Clean Up

            delete [] pData;
        }
        else
            break;
    }

    return false;

}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

mohamad hajibegloo


Member
I had worked as programmer,project manager,web developer for more than 3 years.
I have worked in university as a teacher for 3 years.
my favorite langueges are : VC++,C#,PHP
Occupation: Engineer
Company: neyshabur azad univeristy
Location: Iran, Islamic Republic Of Iran, Islamic Republic Of

Other popular Internet / Network articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 5 of 5 (Total in Forum: 5) (Refresh)FirstPrevNext
Generalcan not to run Pinmembermiki23420:37 3 May '09  
GeneralHow to use it? Pinmemberlsf_200822:04 29 Aug '07  
GeneralThanks Pinmemberbraveboy21:02 11 Apr '07  
Generalnot easy to use Pinmemberhorse199719:02 10 Sep '06  
GeneralUnicode Pinmemberthelvaci21:23 27 Feb '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 30 Dec 2004
Editor: Smitha Vijayan
Copyright 2004 by mohamad hajibegloo
Everything else Copyright © CodeProject, 1999-2009
Web10 | Advertise on the Code Project