Solved

Server/Client Socket programming

Posted on 2014-10-21
11
148 Views
Last Modified: 2015-03-12
Hi,
 I am trying to write a server/ multi client application with visual studio 2010 c++ unmanaged, I can create the server fine and connect the clients fine but I can not successfully detect if a client has disconnected I have been trying to use FD_SET, FD_ISSET and select(..) but I still can not detect when a client has disconnected can anyone point me in the right direction or show me some sample code that dose show how to successfully detect if one of the clients has disconnected or lost its connection.
Thanks
Nigel
0
Comment
Question by:nchannon
11 Comments
 
LVL 86

Expert Comment

by:jkr
Comment Utility
While there is no way to automatically be notified when a client loses the connection, you can always call 'getpeername()' (http://msdn.microsoft.com/en-US/library/windows/desktop/ms738533%28v=vs.85%29.aspx) to check if you still have a connection, e.g.

BOOL CheckIfConnected(SOCKET s) {

  struct sockaddr addr;
  int len;
  len = sizeof(addr);
  return 0 == getpeername(s, (struct sockaddr*)&addr, &len);
}

Open in new window

0
 

Author Comment

by:nchannon
Comment Utility
Hi jkr,
 I tried this approach also but when I physically disconnect a client getpeername still returned 0 on the socket number any idea why this would happen
Thanks
0
 
LVL 19

Expert Comment

by:mrwad99
Comment Utility
My knowledge of select() is a little rusty, but when you call select(), is the socket that closed not returned in the SET that you passed for read notifications?  If it is; in that case, call recv() on it which should return -1 which means the socket is closed.

A much better way is to use IO completion ports, which do tell you immediately when a socket is closed; however their use is normally reserved for heavyweight servers requiring peak performance.
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
the socket that closed not returned in the SET that you passed for read notifications?  If it is; in that case, call recv() on it which should return -1
if the socket was not closed the recv would block infinitely.

to check sockets whether they were still connected, you may periodically call select with minimal timeout, and on timeout  set the socket to non-blocking, then call recv. the return will be -1 (socket error) but the errno (or WSAGetLastError on windows) would return EWOULDBLOCK (WSAEWOULDBLOCK on windows) if the socket is still connected.

here the code for winsock to set the socket non-blocking

unsigned long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);
...
// reset to blocking mode
iMode = 0;
ioctlsocket(Socket,FIONBIO,&iMode);

Open in new window


for Linux you would have

int oldflags = fcntl(sockfd, F_GETFL);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
....
fcntl(sockfd, F_SETFL, oldflags); 

Open in new window


note, from my experience disconnected clients don't make much troubles. if you often sent messages to all the clients connected or periodically would do some kind of heart-beat check, you immediately would find out whether they still are connected or not. the open socket handle in your server requires minimal overhead. so, beside you would run short on socket handles, it should be good, if you do the above check on idle time and after longer periods.  

Sara
0
 

Author Comment

by:nchannon
Comment Utility
Hi Thanks for the reply, I have tried the blocking and non blocking approach as well but I still do not get -1 from recv() when I disconnect the client each time. Some times I get -1 but its not consistent eg: sometimes I get -1 from recv() immediately other times it could take 20 ~ 30 seconds or not at all.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 32

Expert Comment

by:sarabande
Comment Utility
how do make the disconnect? do you pull the cable?

Sara
0
 

Author Comment

by:nchannon
Comment Utility
Hi Sara,
 Correct I physically disconnect the client, The client is connected via wifi local internal network on my router I just pull the wifi connection on the client side so the connection is fully terminated. This is what I need to do so the server can update its client list and remove any clients no longer connected.
Regards
Nigel
0
 

Author Comment

by:nchannon
Comment Utility
Hi I have come across  this link http://www.codeproject.com/Articles/20570/Scalable-Servers-with-IO-Completion-Ports-and-How which works a dream but im am not familiar with using templates. I have adapted this example to an MFC dialog test app and can connect, receive and detect immediately when a client disconnects but as I mentioned I am not familiar with using templates and was wondering if someone can take a look at this ling and maybe point me in the correct direction on the best way to implement the templates to an MFC dialog and show who to send data to the clients using this approach.
Regards
Nigel
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
Correct I physically disconnect the client
the problem with a physical disconnection is that the tcp/ip subsystem is not immediately recognizing that as a fatal error but handles it like a temporary failure. because of that connected server won't be notified even if they try to read from the client socket. you may check whether an orderly shutdown of the connection by the client would solve the issue and if yes, assess whether physical disconnection is a realistic use case which requires to being handled. as suggested, you could do a heart-beat check yourself, if you need a faster recognition.

was wondering if someone can take a look at this link
I looked on the link and as I see the template type used is only an option which allows to pass an own (class) object to the ClientSocket class:

The only limitation with the class/structure used as an attachment is: it should have a default (no arguments) constructer and a Clear() method (to perform internal cleaning). There are a few other requirements, but they will be described later
a bigger problem (as templates) for usage in a mfc dialog surely is that the solution is multi-threaded what means that the dialog (thread) cannot directly be server or client but only the user interface for either of the two.

to say more, you should describe what you want to do and what requirements you have. in any case the templates probably is one of the smallest problems.

Sara
0
 

Author Comment

by:nchannon
Comment Utility
Hi Sara,
 Thanks for taking a look at the templates, What I am trying to achieve is the following:
I have developed my own wifi hardware device meaning I have built my own circuit board and developed the firmware my self that uses a wifi 2.4Mhz chip from Microchip, this is what I am referring to as the clients. These boards then connect via wifi to the server ( being an application running on win7 ) These client simply connect to the server via a router and send a connect status that include the mac address IP, firmware version, model name etc.. these are just text strings that the server receives which are then stored on the server in a vector array along with the socket that has been assigned to the client by the server this now allows the server to extinguish between clients for later use. The main server is a voice activated application for the disability where they say a command which is associated to a specific client (hardware device) eg: "turn on the TV in the bedroom" this in turn will tell the server that the client (hardware device ) is located in the bedroom with the associated socket assigned to it which then invokes the socket send(..) function and send the infra red pulse signal (binary) associated with turning the TV on to the client (hardware device) which in turns fires the infra red pulses that would normally be sent by the TV's remote control. this all works fine except if the client (hardware device ) drops its connection I need to detect this and warn the disable end user that there command will not be sent due to the device in the bedroom is no longer responding and to have it checked by an engineer or someone that understands the hardware eg: is it still got power to the client device.  
I think this explains what im trying to achieve by detecting the connection loss.
When I tried to use the template described above it detected the clients disconnection immediately and with my small amount of knowledge of templates I added a SendMessage(..) to the template header server_service.h see below:
  case _CLOSE:
                Log::LogMessage( L"CloseSocket request %d.\n", m_pSocket->GetSocket() );
                m_pSEvent->OnClose( m_pSocket, m_pOverlap, m_pServerSocket, m_pHIocp );
                // Make sure (double check) the socket
                // is closed.
                SendMessage(theApp.hwndMainParent, WM_SOCKET_DISCONNECT, 1, m_pSocket->m_ClientSock);
                m_pServerSocket->Release( m_pSocket );
                break;

            case _ACCEPT:
                m_pSEvent->OnAccept( m_pSocket, m_pOverlap, m_pServerSocket, m_pHIocp );
                SendMessage(theApp.hwndMainParent, WM_SOCKET_CONNECT, 0, m_pSocket->m_ClientSock);
                break;

            case _READ:
                m_pSEvent->OnReadFinalized( m_pSocket, m_pOverlap, m_dwBytesTransferred,
                    m_pServerSocket, m_pHIocp );

                SendMessage(theApp.hwndMainParent, WM_SOCKET_READ, (WPARAM)(char*)m_pOverlap->DataBuf.buf, m_pSocket->m_ClientSock);
                break;

Open in new window


when the event _CLOSE is fired I send the message along with the socket id back to the parent MFC dialog and processed the data accordingly eg: remove the client from the vector array which updates the server records. this is also the same for the event _READ this all works fine within my MFC app. I wasn't able to get the templates to work with child windows so this is why I pumped the message back to the the main parent dlg.

My main issue for me here is I could not get the event _SEND to respond mainly to my lack of understanding and using templates and this is where if possible I need help.
Thanks again and if you could add any light to this template I would be very grateful.
Kind Regards
Nigel
0
 
LVL 32

Accepted Solution

by:
sarabande earned 500 total points
Comment Utility
below is the sample 'attachment' class used as template parameter for the socket classes

it has members  last action date/time and string buffer and functions Commit, Clear, ResetTime and GetTimeElapsed.

the socket classes will use an object of the template type to fill the string buffer with the data read from socket and to notify

struct Attachment {
    volatile time_t    tmLastActionTime;
    char            sString<BUFF_SIZE>;
    DWORD           dwStringSize; // current string's size


    Attachment() { Clear(); };

    bool Commit( DWORD dwBytesTransferred ) {
        DWORD dwSize = dwStringSize + dwBytesTransferred;
    
        if ( dwBytesTransferred <= 0 ) return false;
        if ( dwSize >= BUFF_SIZE ) return false;

        dwStringSize = dwSize;
        sString[dwStringSize] = 0;
        return true;
    };

    // as requested by the API of the framework

    void Clear() { memset(this, 0, sizeof(Attachment) ); };

    // as requested by the API of the framework

    void ResetTime( bool toZero ) { 
        if (toZero) tmLastActionTime = 0;
        else {
            time_t    lLastActionTime;
            time(&lLastActionTime); 
            tmLastActionTime = lLastActionTime;
        }
    };

    // as requested by the API of the framework

    long GetTimeElapsed() {
        time_t tmCurrentTime;

        if (0 == tmLastActionTime) return 0;

        time(&tmCurrentTime);
        return (tmCurrentTime - tmLastActionTime);
    };
};

Open in new window


to make the template classes real classes you simply do like (code also from  your link)

typedef ClientSocket<Attachment> MyCSocket;
typedef ServerSocket<Attachment> MySSocket;
typedef IOCPSimple<Attachment> MyIOCPSimple;
typedef ISockEvent<Attachment> MyISockEvent;
typedef ServerService<Attachment> MyServerService;

Open in new window


so, the template is nothing you have to care much about. it is a means to get notified immediately in the threads rather then waiting for events only and to get or put buffers from and to server class.

the following code from sample shows how the template class could be used:

// A template class allowing re-using of the memory blocks.
template<class T>
class QueuedBlocks {
private:
    QMutex       m_qMutex;
    set< T* >    m_quBlocks;
    vector< T* > m_allBlocks;

public:
    QueuedBlocks(int nInitSize = 1): 
        m_qMutex(), m_quBlocks(), m_allBlocks() {...};

    // get a free block from the queue, if one cannot be found
    // then NULL is returned

    T* GetFromQueue() {...};

    // get a free block from the queue, if one cannot be found
    // then a new one is created

    T* Get() {...};

    // Release the used block, place it
    // back to the queue. For performance reason,
    // we assume that the block was previously taken
    // from the queue.

    void Release(T* t) {...};

    // Return all the blocks ever allocated.

    vector<T*> *GetBlocks() {...};

    ~QueuedBlocks() {...};
};

Open in new window


with

QueuedBlocks<Attachment> blocks(100);

Open in new window

you would define a queue with maximum 100 'attachment' objects. the class has two containers - set and a vector - where it holds pointers to the Attachment objects. the set gives fast access by pointer (address), while the vector gives indexed access to the pointers such that the order the objects were created will be kept.

you can copy the code for the attachment as it is and - as far as I see - can ignore it until you learned more on how to use them for your purposes.

My main issue for me here is I could not get the event _SEND to respond mainly to my lack of understanding and using templates and this is where if possible I need help.
the _SEND isn't same category as _READ and _CLOSE. a send notification only can be fired if your program actively "sends" data to a client or server.

the send would be done calling MySServer::SendToSocket function (where MySServer is typedef'd as ServerSocket<Attachment>). you see a sample of the call in the sample function OnReadFinalized, which would be called after a read operation successfully was finished (probably the same as catching the _READ in your code).

virtual void OnReadFinalized( MyCSocket *pSocket, 
                MYOVERLAPPED *pOverlap, DWORD dwBytesTransferred, 
                MySSocket *pServerSocket, MyIOCPSimple *pHIocp ) {
        int nRet;
        DWORD dwSize, dwPos;
        char *temp;

        // finalize the filling of the buffer

        pSocket->GetAttachment()->Commit( dwBytesTransferred );

        dwSize = BUFF_SIZE - 1;
        dwPos = pSocket->GetAttachment()->dwStringSize;
        temp = pSocket->GetAttachment()->sString;

        nRet = pSocket->ReadFromSocket(    temp + dwPos, dwSize - dwPos );
        pSocket->GetAttachment()->ResetTime( false );

        if ( nRet == SOCKET_ERROR ) {
            pServerSocket->Release( pSocket );
        }
        else if ( nRet == RECV_BUFFER_EMPTY ) {
            // means that dwSize - dwPos == 0, so send the data 

            // back to the socket


            nRet = pSocket->WriteToSocket( temp, dwSize );
            if ( nRet == SOCKET_ERROR ) {
                pServerSocket->Release( pSocket );
            }
        }
    };

Open in new window

you see that the code uses a ClientSocket instance (MyCSocket) and the associated 'attachment' buffer to get the data read from socket and then writes back to client with pServer->WriteToSocket. if the send operation was successful, the OnWriteFinalized function was called by the server.

I didn't download the full source so far, so if you have detail questions to the code you would need to post the code you have problem with and refer to the line or statement where you have issues with.

Sara
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now