Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

There is a server that responds to requests on a socket. The client has functions to emit requests and functions to handle responses from the server.

The problem is that the request sending function and the response handling function are two unrelated functions. Given a server response X, how can I know whether it's a response to request X or some other request Y?

I would like to make a construct that would ensure that response X is definitely the answer to request X and also to make a function requestX() that returns response X and not some other response Y.

This question is mostly about the general programming approach and not about any specific language construct. Preferably, though, the answer would involve Ruby, TCP sockets, and PHP.

My code so far:

require 'socket'

class TheConnection
    def initialize(config)
        @config = config
    end
    def send(s)
        toConsole("--> #{s}")
        @conn.send "#{s}\n", 0 
    end
    def connect()
        # Connect to the server
        begin
            @conn = TCPSocket.open(@config['server'], @config['port'])
        rescue Interrupt
        rescue Exception => detail
            toConsole('Exception: ' + detail.message())
            print detail.backtrace.join('\n')
            retry
        end
    end
    def getSpecificAnswer(input)
        send "GET #{input}"
    end
    def handle_server_input(s)
        case s.strip
            when /^Hello. (.*)$/i
                toConsole "[ Server says hello ]"
                send "Hello to you too! #{$1}"              
            else
                toConsole(s)
        end
    end
    def main_loop()
        while true
            ready = select([@conn, $stdin], nil, nil, nil)
            next if !ready
            for s in ready[0]
                if s == $stdin then
                    return if $stdin.eof
                    s = $stdin.gets
                    send s
                elsif s == @conn then
                    return if @conn.eof
                    s = @conn.gets
                    handle_server_input(s)
                end
            end
        end
    end
    def toConsole(msg)
        t = Time.new
        puts t.strftime("[%H:%M:%S]") + ' ' + msg
    end
end
@config = Hash[
    'server'=>'test.server.com',
    'port'=>'2020'
]
$conn = TheConnection.new(@config)
$conn.connect()
$conn.getSpecificAnswer('itemsX')

begin
    $conn.main_loop()
rescue Interrupt
rescue Exception => detail
    $conn.toConsole('Exception: ' + detail.message())
    print detail.backtrace.join('\n')
    retry
end
share|improve this question
3  
Hi Deele, some of us are finding it difficult to follow your post; however, that doesn't mean you don't have a good question. Can you narrow down your example or post a more concise example, as well as eliminate the excessive use of commas? Just so you know, your question may get closed, but feel free to continue to edit it afterwards and then flag it for reopening. Hope this helps! Good luck! :) –  jmort253 Aug 30 '12 at 4:04
1  
We've edited this one a bunch and I think it makes sense now. It might even mean what the submitter intended. :-) –  Stuart Marks Aug 31 '12 at 1:00
add comment

2 Answers 2

I think I understand the question you're asking. Is it:

I have a client-server system in which the client can have multiple requests pending simultaneously. When the client receives a response, how can it tell which request corresponds to this response?

If so, there are several ways to proceed. Note that in the following discussion we distinguish between the protocol itself vs. the programming interface (API) that applications use to drive the protocol.

0. Use an established protocol.

There are many subtleties involved in developing protocols. Existing protocols such as HTTP may have solved these issues satisfactorily for your application already, and there are many APIs for it already available. I'm with BicycleDude, use an existing protocol if possible. However, if you can't use an existing protocol for some reason, read on.

1. Make the protocol and API fully synchronous.

This is the simplest approach. When the client issues a request, it blocks reading from the socket until it receives the response -- the entire response. Then it returns the response to the caller. This is changing the protocol so that there is at most one request pending at any given time. The response received unambiguously corresponds to the request just sent. The API is simple, because the caller issues the request and server's response can be the return value of the function called to issue the request.

The problem is that it's slow. Each request suffers round-trip latency to the server. The client can't do anything else while it's waiting. (Unless the client is multi-threaded.)

You should seriously consider this approach (if you've decided not to reuse an existing protocol). This is similar in style to RPC (Remote Procedure Calls). The latency issues can be irritating, but the implementation and programming model are simple. If you decide to step away from being fully synchronous, things get complicated very fast.

2. Allow pipelining in the protocol, and make the API asynchronous.

"Pipelining" means that multiple requests can be pending, but that the server is required to process and to respond to each request in order. The client keeps track of which requests are pending and, since the responses come in order, it knows which request corresponds to which response.

There is great diagram on the Wikipedia article for HTTP pipelining. See, you really should consider using HTTP. :-)

The programming model gets more complicated now. When the client issues a request Request1, the call returns immediately and doesn't wait for the corresponding response Response1. Now the application can continue doing other work and eventually issue Request2 in the same way. How does the application get its responses? The usual way is for the API to return some object that represents the pending request. When the application wants to get the response for that request, it makes a call on that object. The pseudo-code would look something like this:

request1 = send_request(...)
...
response1 = request1.get_response()

Now, note that the application can ask for responses in a different order from which the requests were issued:

request1 = send_request(...)
request2 = send_request(...)
...
response2 = request2.get_response()

How does this work? The client will receive response1 over the network first, but that's not what the application is asking for -- it's asking for response2. So the client (presumably somewhere in a library) will have to buffer up response1 and then read, possibly waiting for, response2 to come in. Now we have a situation where the library needs to buffer up a potentially arbitrary amount of responses until the application asks for those specific responses. If the application forgets to do so, well, that's a memory leak. The library may also need to cancel a pending request; this doesn't really cancel it, but basically just tells the library to discard that particular response.

3. Make the protocol asynchronous.

This variation allows the server to respond to requests out-of-order. This could happen if the server processes its requests using a thread pool. Whenever a server thread completes its work, it sends its response, regardless of the order in which the requests were received.

So, the client might issue request1 and then request2, but the server might send response2 first. This variation has the same client-side buffering and request-response tracking issues, but now the protocol itself has to keep track of which response corresponds to which request. The usual way to do this is with sequence numbers or IDs. The client sends a sequence number along with every request. This number must be unique, at least unique enough so that no two pending requests ever have the same ID. Then, the server has to put this ID number in every response.

Still other variations are possible, for example, allowing the server to send zero or more than one response to each request, or allowing the server to send messages spontaneously (that is, not in response to any particular request).

Good luck!

share|improve this answer
    
I would recommend using UUIDs over sequence numbers to identify requests, it gives you many more options for scaling up, and, simplifies any disaster recovery and fail over implementations. –  James Anderson Aug 31 '12 at 3:42
    
@JamesAnderson UUIDs would be nearly wasted, since this secquence only has to be unique for the client. If you are using UUID type 1/2, then the first 6.5 bytes will never change. Sequence numbers and/or timestamps are more than sufficient. –  Chris Pitman Aug 31 '12 at 4:56
    
@JamesAnderson Actually, the above was even a little optimisitic. For any real timespan that a single "session" will span, most of the timestamp will be the same too! –  Chris Pitman Aug 31 '12 at 5:03
add comment

You mentioned that the question is more about the programming method than the language. What I'm concerned about this seems to be a reinvention of stuff that already exists out there? I mean what about building servers that support REST or SOAP apis? What about querying servers using AJAX? There's a bunch of stuff that's out there and you'll be conforming to establish industry protocols and that means you can rapidly design and test your servers using HTML and JavaScript.

share|improve this answer
    
The question is about constant data stream servers, when you keep connection alive, not connect-ask-disconnect, like is it with REST/SOAP/SNMP/etc. –  Deele Feb 15 '12 at 22:04
    
Right, okay, that's a little different. But, I will still suggest to avoid reinventing a protocol. For constantly connected protocols perhaps you can leverage from FTP or TELNET protocols and their respective software. Also REST and SOAP apis can still be leveraged if you simulated HTTP persisted connections (i.e. keep-alive = true). –  Stephen Quan Feb 15 '12 at 23:39
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.