Solved

Server/Client Socket programming

Posted on 2014-10-21
11
158 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
11 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 40394955
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
ID: 40395977
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
ID: 40396536
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 34

Expert Comment

by:sarabande
ID: 40396975
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
ID: 40400529
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
 
LVL 34

Expert Comment

by:sarabande
ID: 40401769
how do make the disconnect? do you pull the cable?

Sara
0
 

Author Comment

by:nchannon
ID: 40401887
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
ID: 40402013
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 34

Expert Comment

by:sarabande
ID: 40406231
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
ID: 40408164
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 34

Accepted Solution

by:
sarabande earned 500 total points
ID: 40408437
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

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

756 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