A client-server architecture in a computer network is one in which several remote processors (clients) request and receive services from a pre-defined host processor (server).
The server waits for any incoming service requests from clients.
Once a request is received, the server services the client. After dealing with a client, the server closes the connection and returns to the waiting state.
In a multithreaded server, the server creates and dispatches a thread to service a client before returning to the waiting state. This allows a single server to accommodate multiple client requests in parallel.
The client requests a server for services. Upon sending a request for service, the client waits for the server to acknowledge the request, after which service is provided to the client.
Once the client request has been handled, the server terminates the connection.
Sockets are key when programming a network.
Sockets are endpoints for sending and receiving data. It is easier to understand if you think of sockets as doors that open into the rooms of both the client and server.
To pass any piece of information between the client and server, we need to know where the respective door is or else, the information will be lost.
Now that we know how both the client and server work, we can write code that encapsulates some logic in sync between them.
Let’s consider an example of how a client-server connection is established while programming. We will be using Java to write a program where the client sends a message to the server. The server receives the message, changes it to uppercase, and sends the updated message back to the client.
import java.net.*; import java.io.*; public class Client { public static void main(String args[]) { try{ // Create socket with port # of server Socket s = new Socket("localhost", 2222); // Attaching input streams to socket InputStream str = s.getInputStream(); InputStreamReader isr = new InputStreamReader(str); BufferedReader br = new BufferedReader(isr); // Attaching output streams to socket OutputStream out = s.getOutputStream(); PrintWriter pw = new PrintWriter(out, true); // Send message to server pw.println("hello world"); // Receive response from server String server_message = br.readLine(); // Print response to screen System.out.println("Server says: " + server_message); br.close(); pw.close(); s.close(); } catch(Exception e){ System.out.println(e); } } }
import java.net.*; import java.io.*; public class Server { public static void main(String args[]) { try{ // Creating Server Socket with same port # as in client ServerSocket ss = new ServerSocket(2222); while(true){ Socket s = ss.accept(); // Blocked here till request received // Attaching input streams to socket InputStream str = s.getInputStream(); InputStreamReader isr = new InputStreamReader(str); BufferedReader br = new BufferedReader(isr); // Attaching output streams to socket OutputStream out = s.getOutputStream(); PrintWriter pw = new PrintWriter(out, true); // Receive client message String client_message = br.readLine(); System.out.println("Client says: " + client_message); // Send response to client String updated_message = client_message.toUpperCase(); pw.println(updated_message); br.close(); pw.close(); s.close(); } } catch(Exception e){ System.out.println(e); } } }
The following steps briefly describe the code above:
Server initiates a ServerSocket
and port number.
Server invokes accept()
method. This method waits until a client connects to the server.
While the server waits, the client instantiates a Socket
object, specifying the server name and port number.
The constructor of the Socket
attempts to connect the client to the specified server.
If the connection is successful, the client can communicate with the server.
On the server’s side, the accept()
method returns a reference to a new socket that is connected to the client’s socket.
Note: When executing the code, always compile and run the server before the client.
RELATED TAGS
CONTRIBUTOR
View all Courses