Concepts / Network Server Basics

Network Server Basics

A server that finishes one client before accepting the next, as the DateServer sample does, can be held up by a single slow or idle connection.

  • Programming

A Line Behind One Counter

Imagine a small shop with one counter and one clerk. The clerk serves a customer from start to finish before turning to the next person in line. If the first customer is quick, nobody minds. If the first customer settles in and talks for an hour, everyone behind them waits for the entire hour. A network server that handles connections one at a time has exactly this problem.

What do you think happens?

In the shop, the first customer stays at the counter for an hour. What happens to the customer standing second in line?

  • They are served right away, one at a time with the first customer

  • They wait until the first customer is finished, which can take the full hour

  • The clerk serves them at the same time as the first customer

Reveal answer
Answer:

They wait until the first customer is finished, which can take the full hour.

A single clerk finishes each customer before turning to the next, so the second customer's wait is set by how long the first customer keeps the clerk busy.

This article follows the same question into the world of network servers. It looks at how a server can be built so that one lingering client does not stop everyone else. The tool for doing this is the thread, but before we look at how threads change the picture, we need to see clearly what goes wrong without them.

Why One Connection Can Hold Up Everyone

The DateServer.java sample program from this course is an extremely simple network server. It does not use threads. Because of that, the server has to finish its work with one client before it is able to accept a connection from a different client. The server is not doing two jobs at once. It works through its connections in order.

Consider how long a single interaction lasts. The exchange with a client might be very brief, and for a simple date service it often is. Even so, we cannot assume every client will behave that way. A client could connect, stay connected for a long time, and keep the server occupied the whole while. In a server with no threads, every client that arrives during that time has to wait.

Serve Client Aconnection stays openClient B waitsnot yet acceptedClient C waitsnot yet acceptedServe Client Bstarts only after AfinishesA finishesB still waitingthen B is served
While the server is busy with one client, what happens to the clients waiting behind it, and how long does each one wait?

The timeline above is an illustration, not a measurement. It shows the ordering rule of a non-threaded server: the clients queue up, and each one is served only after the one ahead of it is done. The exact waiting time depends on how long the first client stays connected, which the server cannot know in advance.

Tracing Three Clients Through a Single-Line Server

Worked example

Three clients arriving at a non-threaded server

Client A connects first and stays connected for a long time without finishing its exchange. Client B and Client C connect while A is still connected. What does the server do with B and C?

  1. 1
    Step 1: Client A is accepted

    The server accepts the connection from Client A and begins its single interaction with that client.

  2. 2
    Step 2: Client B arrives

    Client B connects while the server is still busy with A. The server is not doing two jobs at once, so B has to wait for its turn.

  3. 3
    Step 3: Client C arrives

    Client C also connects during the same period and joins the wait. Nothing about C's arrival changes the order of service.

  4. 4
    Step 4: Client A finally finishes

    Only after A's exchange is complete does the server move on to the next connection, which is B. C continues to wait behind B.

Result

B and C are both held up by A. Their wait is set by how long A keeps the server occupied, not by how long B or C themselves need.

Giving Each Connection Its Own Thread

A threaded server changes the ordering problem. Instead of one path of execution that must finish with each client in turn, the server can use threads so that it deals with several clients at the same time. A thread is an independent path of execution, so while one thread is waiting on one client, another thread can be working with a different client. The server is no longer locked to a single line.

Client 1sends a requestClient 2sends a requestAccept loopreceives each connectionThread for Client 1works with Client 1Thread for Client 2works with Client 2connectshands off connectionconnectshands off connection
How does the accept loop hand each new connection to its own thread, so that several clients are being served at the same moment?

The diagram shows the shape of this arrangement. Several clients send requests to one server, and the server gives each connection its own thread. Each thread carries on with its own client, so the progress of one client does not dictate when another client can be served. The accept step is the part that receives each new connection, and each connection then goes to its own thread.

When a Client Sends Nothing Useful

The source gives a name to the problem case. A misbehaving client is one that stays connected without sending the data the server expects. This is not a client that sends bad data. It is a client that sends nothing useful while keeping the connection open. From the server's point of view, it is waiting for input that never arrives.

Follow the thread that is paired with such a client. The thread is waiting on a connection that is not producing the input it needs. In the source's words, this can hang up that thread indefinitely. The important point is what does not happen: the other threads keep going, and they continue to serve their own clients.

Connection acceptedthread created for clientWaiting for expecteddatathread is blockedExpected data arrivesdoes not happen for astalled clientClient servedreached only if dataarrivesOther threadskeep serving their ownclientsthread reads from connectionwaits for inputyes
What state does a client's thread move into when it waits for data that never arrives, and how does that differ from the threads still doing work?

The diagram traces the path of the stalled client on the left and leaves the other threads as a separate path. The stalled thread sits in its waiting state, while the other threads are free to move through their own work. That separation is the reason one lingering client does not stop everyone else.

Converting DateServer into a Threaded Server

The source uses DateServer as a starting point for converting a simple server into a threaded one. Converting a server to use threads changes the server's structure, while the client program can usually stay the same. The same techniques are meant to apply to more complicated servers.

The source also admits that the conversion is not very useful for such a simple server. The reason is that DateServer's interaction with each client is short, so the benefit of threads hardly shows. The value of the technique becomes clearer when a client's interaction can last a long time.

FeatureNon-threaded DateServerThreaded server
How clients are handledOne after another, in sequenceSeveral at the same time, one thread each
Effect of a lingering clientHolds up every client behind itOnly its own thread is hung up
Change to the client programNot applicable to this comparisonUsually none
Benefit for a short interactionHardly noticeableHardly noticeable

The two server designs differ most in how a slow or idle connection affects other clients.

Mistakes Beginners Make About Threads

  • Common mistake

    Assuming a server with no threads can still serve clients in parallel

    Why it fails

    The DateServer works through its connections in order. It is not doing two jobs at once.

    Do this instead

    Recognize that a non-threaded server finishes one client before it accepts the next.

  • Common mistake

    Thinking a slow client only delays itself

    Why it fails

    Without threads, every client that arrives while a lingering client is connected has to wait.

    Do this instead

    Trace the queue: the wait of later clients depends on how long the first client keeps the server busy.

  • Common mistake

    Believing a stalled client makes the whole server stop

    Why it fails

    A misbehaving client can hang up its own thread indefinitely, but other threads can continue with other clients.

    Do this instead

    Separate the stalled thread from the other threads when you trace what the server is doing.

  • Common mistake

    Treating threads as a guaranteed speed-up

    Why it fails

    The source is explicit that the diagram does not say the server is always fast and that threads are not free.

    Do this instead

    Describe threads as allowing several conversations to be in progress together, not as making every client faster.

Tracing a Stalled Client by Hand

MEDIUM

A server uses one thread per client. Client X connects and then sends nothing while keeping its connection open. Client Y connects later and sends the data the server expects. Trace what happens to X's thread and to Y's thread, and say which client is served and why.

Hints
  • Ask which thread is waiting for input that never arrives.
  • Ask whether Y's thread depends on X's thread to make progress.
  • Compare your answer with the state diagram in the stalled client section.

Key Takeaways

  • A server that finishes one client before accepting the next, like the non-threaded DateServer, can be held up by a single slow or idle connection.
  • Giving each connection its own thread lets the server work with several clients at the same time, because each thread is an independent path of execution.
  • A client that stays connected without sending the expected data can hang up its own thread indefinitely, but other threads can continue serving other clients.
  • Converting a server to use threads changes its structure while the client program can usually stay the same, though the benefit is small for short interactions like DateServer.