tags:

views:

222

answers:

2

I'm building a (LAN) network application, so there is always the possibility that a connection will be disconnected, for various possible reasons. I am trying to think of a good design for handling this issue, such that it doesn't affect the rest of the application. I wrote a quick thing to try to do it, but I think it can be enhanced a lot. I appreciate your help and experience about the best way to handle this issue.

This is my first trial:

class ConnectionWrapper {
    NetworkStream stream;
    StreamReader reader;
    Endpoint endPoint;
    bool endOfStream;
    int maxRetries = 5;

    public void connect() {
        // ... code to initialize a (TCP) socket to endPoint
        this.stream = new NetworkStream(socket, true);
        this.reader = new StreamReader(stream);
    }

    string readNextMsg() {
        try {
            string msg = reader.ReadLine();
            if (msg == "EOF") endOfStream = true;
            return msg;
        }
        catch (IOException e) {
            Exception ex = e;
            while (maxRetries-- > 0) {
                try { connect(); ex = null; }
                catch (Exception e2) { ex = e2; }
            }
            if (x != null) throw ex;
        }
    }
}

Not very elegant, and probably not the best that can be done. Could you please share your experience, and may be even suggest an existing library?

Thank you.

+2  A: 

I honestly don't think you should let the connection wrapper contain logic to handle its own connection policy. I think this should be done from outside of this class, and especially not in the catch statement. Have some kind of ConnectionController object to deal with whether the connection should be retried once it fails.

Kezzer
Thank you. I agree that the place shouldn't be the catch clause, but it's my lack of experience that makes me do so. :)If you could spare time to give an example, I'd be thankful.
Hosam Aly
+1  A: 

I was going to edit my post, but this should be completely separate from my last one.

Your logic is all wrong in my opinion, you should have a thread within the ConnectionWrapper which spins on the StreamReader pulling off messages and placing them on a queue. This queue then notifies listeners of a change. The listeners then go and retrieve the data themselves and decide what needs to be done with them.

class ConnectionWrapper {
    NetworkStream stream;
    StreamReader reader;
    Endpoint endPoint;
    bool endOfStream;
    int maxRetries = 5;
    ArrayList arr;

    public void connect() {
        // ... code to initialize a (TCP) socket to endPoint
        this.stream = new NetworkStream(socket, true);
        this.reader = new StreamReader(stream);
    }

    private void initReceiverThread() {
        String line;

        while(stream.isConnected() && (line = reader.readLine()) != null) {
           // notify observers of a change
           arr.add(line);
        }
    }
}

This is pseudo-code I warn you, I've never done this in C#. A typical reader actually waits on a readLine statement, so the while loop won't go crazy. It's also best to put initReceiverThread code in a Thread, that way it won't block the rest of the application. By notifying the observers of a change they can then go and get the ArrayList by doing something like myConnectionWrapper.getMessages(); which will return an ArrayList, but also clearing out the ArrayList at the same time, like so:

public ArrayList getMessages() {
     ArrayList temp = arr;
     arr.clear();
     return temp;
}

That way you get ALL of the messages and clear them off the queue.

I've written network clients before, and this is the general design of one. You'll have two threads constantly spinning, one to receiver messages, and one to send them.

The logic should be dealt with some kind of manager code to determine whether to continue, or reconnect or whatever you want to do.

Kezzer
Thank you @Kezzer. My wrapper class is actually being used in a way similar to what you describe. A thread uses it to read messages and add them to a queue, which another thread uses to process inputs. However, I want to encapsulate all connection logic in the connection wrapper class. ...
Hosam Aly
... The `Connected` property of the socket (not the stream) isn't useful for this particular issue. According to its documentation in MSDN, it returns the connection status as of the last I/O operation. The same page shows how to know whether a socket is connected, by sending a zero-byte array. ...
Hosam Aly
... Finally, your "getMessages()" method would clear the returned array, as temp and arr refer to the same object. Maybe you meant "temp = arr.Clone()" or something similar.
Hosam Aly
Well, that depends on how you decide to deal with the inbound message queue. In my implementation I give the queue to a master controller, so clearing the queue once it is retrieved is actually the logical step. Otherwise, how can you tell what's new and what's not?
Kezzer
To tell what's new and what's not, I use a `volatile` count for the queue, and a (thread-local) count for consumed messages.
Hosam Aly
I just don't like the idea of storing every single inbound message on a queue. For the apps I develop they would grow tremendously causing large memory overhead, especially seeing as though the data would be duplicated when passed to controllers.
Kezzer
When there is only one consumer thread, the consumer can (virtually) remove elements from the queue (list in my case; by setting them to null). The elements are being passed by reference, so no memory overhead there. Moreover, in my application memory is of least importance (as opposed to speed).
Hosam Aly