Lecture Notes for Client-Server Interfaces

8 February 2002 - Servers


  1. more complex that clients

    1. never stops

    2. handles multiple requests, somehow

  2. architectural issues

    1. handling multiple requests - concurrent vs iterative

      1. real or simulated concurrency

      2. design, implementation, operation

      3. concurrent harder than iterative - but not that much harder

      4. concurrent much harder than iterative - primitive concepts, language support, tools; subtle errors, difficult to reproduce

      5. concurrent faster than iteration - but perhaps not that much better; latency over throughput; iteration responds better to more hardware

    2. communication style - confusion reigns

      1. point to point vs multiplex-multicast

      2. reliable vs unreliable - connection, delivery, and shut-down

      3. flow control vs firehose

      4. stream vs datagram

      5. you only get two choices - trade-offs conflict

      6. tcp servers - reliable at the protocol; resource use

      7. udp servers - lightweight; reliable at the server, expensive and hard

    3. stateless vs stateful servers

      1. reliability and performance

      2. state creeps in on little cats' feet - caching

      3. lost state wastes resources and causes bloat

    4. service time vs arrival rate

    5. the quad design space - connection type x concurrency

  3. iterative servers

    1. simpler, resource light, a potential bottleneck

    2. connection-oriented

      1. listener <- socket()
        bind(listener, ipa, pno)
        listen(listener)
        loop {
          active <- accept()
          loop {
            msg <- read(active)
            rsp <- f(msg)
            write(active, rsp)
            }
          close(active)
          }
        

      2. where to listen - at any interface (INADDR_ANY); at any port (0, unlikely)

      3. no addresses necessary - everything's in the connection

    3. connection-less

      1. active <- socket()
        bind(active, ipa, pno)
        loop {
          msg <- recvfrom(active, requester)
          rsp <- f(msg)
          sendto(active, rsp, requester)
          }
        

      2. where to listen - as above

      3. the requester's address must be retrieved from the system.

  4. concurrent servers

    1. increasing complexity but improved performance

      1. well, maybe - certainly on io-bound communication

      2. but - concurrency management overhead

    2. master-slave architecture

      1. also known as the bag o' tasks

      2. general approach - master controls the listener socket; slaves handle the active sockets; note connection-oriented description

      3. connectionless, concurrent server architecture - mostly pointless without application protocol support

        1. master creates the active socket and receives the requests (messages)

        2. master demultiplexes the requests to the slaves

        3. slaves process the request and send back the reply

        4. how many slaves -

        5. the active socket is a shared resource - responder contention

      4. connection-oriented, concurrent architecture

        1. master creates the listening socket and accepts connections

        2. each connection accepted is farmed out to a slave

        3. the slave handles and closes the connection

      5. the slaves

        1. from where do they come - fork or threads

        2. how many of them are there - resource limitations

        3. how long are the around - start-up tear-down overhead

    3. simulating concurrency - a.k.a. event-driven concurrency

      1. osterhout's paper

      2. simpler, less resource intensive, good latency and throughput

      3. select or poll driven

  5. trade offs

    1. iterative vs. concurrent

      1. iterative - simple design, simple implementation, good throughput

      2. concurrent - complex design, complex implementation, good latency

    2. real vs. apparent concurrency

      1. context switch costs, information sharing costs

  6. server deadlock - blocking on io calls

    1. single thread hangs; multi-thread wastes resources

    2. misbehaving clients

    3. can be dealt with using signals and timers in unix


This page last modified on 12 February 2002.