Click here to Skip to main content
Click here to Skip to main content

Peer2Peer socket sample

, 30 Dec 2004
Rate this:
Please Sign up or sign in to vote.
A fully error handled and easy to use peer2peer2 library.

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

Share

About the Author

mohammad hajibegloo
Engineer neyshabur azad univeristy
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
I had worked as programmer,project manager,web developer for more than 3 years, and have worked on programming personaly for more than 10 years.
I have worked in university as a teacher for 8 years.
my favorite langueges are : VC++,C#,ASP.NET,PHP

Comments and Discussions

 
QuestionNot able to use it Pinmemberns_rana1313-Mar-13 1:31 
Questionexciting! Pinmemberyanghongbing31-May-12 6:59 
Questioncan not to run Pinmembermiki2343-May-09 20:37 
QuestionHow to use it? Pinmemberlsf_200829-Aug-07 22:04 
GeneralThanks Pinmemberbraveboy11-Apr-07 21:02 
Generalnot easy to use Pinmemberhorse199710-Sep-06 19:02 
GeneralUnicode Pinmemberthelvaci27-Feb-06 21:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 31 Dec 2004
Article Copyright 2004 by mohammad hajibegloo
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid