Client Server
- 75% developed as of May 2, 2014 Threads and Runnables
- 75% developed as of May 2, 2014 Basic Synchronization
- 75% developed as of May 2, 2014 Client Server Programming
- 25% developed as of May 2, 2014 Remote Method Invocation (RMI)
- 0% developed as of May 2, 2014 Enterprise JavaBean Programming (EJB)
- 0% developed as of May 2, 2014 Java Spaces Programming (Jini)
In 1990s, the trend was moving away from Mainframe computing to Client/Server as the price of Unix servers dropped. The database access and some business logic were centralized on the back-end server, collecting data from the user program was installed on the front-end users' "client" computers. In the Java world there are three main ways the front-end and the back-end can communicate.
- The client application uses JDBC (Java DataBase Connectivity API) to connect to the data base server, (Limited business logic on the back-end, unless using Stored procedures).
- The client application uses RMI (Remote Method Invocation) to communicate with the back-end.
- The client application uses a socket connection to communicate with the back-end.
Socket Connection Example
[edit | edit source ]This page shows an example of a socket connection.
Create a Server
[edit | edit source ]The Java language was developed having network computing in mind. For this reason it is very easy to create a server program. A server is a piece of code that runs all the time listening on a particular port on the computer for incoming requests. When a request arrives, it starts a new thread to service the request.
See the following example:
Listening on a port
[edit | edit source ]- ComServer
- class is for listening on a port for a client.
importjava.net.ServerSocket; /** * -- Main Server Class; Listening on a port for client; If there is a client, * starts a new Thread and goes back to listening for further clients. -- */ publicclass ComServer { staticbooleanGL_listening=true; /** * -- Main program to start the Server -- */ publicstaticvoidmain(String[]args)throwsIOException { ComServersrv=newComServer(); srv.listen(); }// --- End of Main Method --- /** * -- Server method; Listen for client -- */ publicintlisten()throwsIOException { ServerSocketserverSocket=null; intiPortNumber=9090; // --- Open the Server Socket where this should listen --- try{ System.out.println("*** Open the listening socket; at:"+iPortNumber+" ***"); serverSocket=newServerSocket(iPortNumber); }catch(IOExceptione){ System.err.println("Could not listen on port:"+iPortNumber); System.exit(1); } while(GL_listening) { ComServerThreadclientServ; // --- Listening for client; If there is a client start a Thread - System.out.println("*** Listen for a Client; at:"+iPortNumber+" ***"); clientServ=newComServerThread(serverSocket.accept()); // --- Service a Client --- System.out.println("*** A Client came; Service it ***"); clientServ.start();/* --- Use for multy Threaded --- */ // clientServ.run(); /* --- Use for Single Threaded --- */ } // --- Close the Server socket; Server exiting --- serverSocket.close(); return0; }// --- End of listen Method --- }// --- End of ComServer Class ---
- ServerSocket( iPortNumber )
- Creates a server socket, bound to the specified port.
- serverSocket.accept()
- Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made. It returns a new Socket.
Service One Client
[edit | edit source ]- ComServerThread
- This class extended from a Thread is responsible to service one client. The Socket connection will be open between the client and server. A simple protocol has to be defined between the client and server, the server has to understand what the client wants from the server. The client will send a terminate command, for which the server will terminate the socket connection. The ComServerThread class is responsible to handle all client requests, until the client sends a terminate command.
/** * -- A class extended from a Thread; Responsible to service one client -- */ class '''ComServerThread'''extendsThread { privateSocketclientSocket=null; COM_DATAtDataFromClient; COM_DATAtDataToClient; ObjectInputStreamoIn; ObjectOutputStreamoOut; /** * -- Constructor -- */ publicComServerThread(Socketsocket) { super("ComServerThread"); this.clientSocket=socket; }// -- End of ComServerThread() constructor -- /** * -- Overrun from the Thread (super) class -- */ publicvoidrun() { try{ // --- Create the Writer; will be used to send data to client --- oOut=newObjectOutputStream(clientSocket.getOutputStream()); // --- Create the Reader; will be used to get data from client --- oIn=newObjectInputStream(clientSocket.getInputStream()); // --- Create a new protocol object --- ComProtocolcomp=newComProtocol(); // --- Send something to client to indicate that server is ready --- tDataToClient='''comp.processInput(null);''' '''sendDataToClient'''(tDataToClient,oOut); // --- Get the data from the client --- while(true) { try{ tDataFromClient='''getDataFromClient(oIn)'''; // --- Parse the request and get the reply --- tDataToClient='''comp.processInput(tDataFromClient);''' // --- Send data to the Client --- '''sendDataToClient'''(tDataToClient,oOut); } catch(EOFExceptione){ System.out.println("Client Disconnected, Bye, Bye"); break; } // --- See if the Client wanted to terminate the connection --- if(tDataToClient.bExit) { System.out.println("Client said Bye. Bye"); break; } } // --- Close resources; This client is gone --- comp.Final(); oOut.close(); oIn.close(); clientSocket.close(); }catch(IOExceptione){ e.printStackTrace(); } }// -- End of run() Method -- /** * Get data from Client */ privatestaticCOM_DATA'''getDataFromClient'''(ObjectInputStreamoIn)throwsIOException { COM_DATAtDataFromClient=null; // --- Initialize variables --- // tDataFromClient = new COM_DATA(); while(tDataFromClient==null) { try{ // --- Read Line Number first -- tDataFromClient=(COM_DATA)oIn.readObject(); }catch(ClassNotFoundExceptione){ System.out.println("ClassNotFound"); } } System.out.println("Get: "+tDataFromClient.comData); returntDataFromClient; }// --- getDataFromClient() Method --- /** * Send data to Client */ privatestaticvoid'''sendDataToClient'''(COM_DATAtDataToClient, ObjectOutputStreamoOut)throwsIOException { System.out.println("Sent: "+tDataToClient.comData); oOut.writeObject(tDataToClient); return; }// -- End of sendDataToClient() Method -- }// --- End of ComServerThread class ---
- COM_DATA tDataFromClient
- This variable will contain the data object from the client.
- COM_DATA tDataToClient
- This variable will contain the data object to be sent to the client.
- sendDataToClient
- This method sends the data object to the client.
- getDataFromClient
- This method gets the data object from the client.
- processInput( tDataFromClient )
- This method of the class
ComProtocol
interprets the client commands and returns the data object that will be sent back to the client.
Handling the request; implements the communication protocol
[edit | edit source ]- ComProtocol
- This class implements, and encapsulates the communication logic (protocol). The protocol is the following:
- The client initiate the connection.
- The server accepts it and sends an acknowledgment notifying that it's ready
- The client sends a request
- The server response based on the request
- ...
- The client sends a
BYE
request - The server acknowledge the
BYE
request and disconnects the socket connection - The client gets the acknowledgment to the
BYE
- The client sends a
- ...
- The client sends a
SHUTDOWN
request - The server acknowledge the
SHUTDOWN
request and disconnects and also stops listening of other clients. - The client gets the acknowledgment to the
SHUTDOWN
- The client sends a
class '''ComProtocol''' { privatestaticfinalintCOM_STATUS_WAITING=0; privatestaticfinalintCOM_STATUS_READY_SENT=1; privatestaticfinalintCOM_STATUS_DATA_SENT=2; privatestaticfinalintCOM_STATUS_WAITING_FOR_TERMINALID=3; privateintstate=COM_STATUS_WAITING; // --- Reference to 'BACK-END' module --- privateMqTeAccessmqTe; ... /** * Create a protokol object; CAll MQ INI function */ publicComProtocol() { intiRet=0; // --- Initialize 'BACK-END' modules --- mqTe.... ... } /** * --- Process the Input and Create the output to the Client --- */ publicCOM_DATAprocessInput(COM_DATAtheInput) { COM_DATAtheOutput; // --- Initialize Variables --- theOutput=newCOM_DATA(); // --- Check if the Clients want to disconnect --- if(theInput!=null) { if(theInput.comData.equals('''"!BYE.@"''')) { // --- The Client wants to terminate; Echo data back to client theOutput.comData="BYE."; // --- Mark the communication to be terminated --- theOutput.bExit=true; // --- Set the internal state to wait for a new client --- state=COM_STATUS_WAITING; // --- Return Data object to be sent to the client --- returntheOutput; } if(theInput.comData.equals('''"!SHUTDOWN.@"''')) { // --- The Client wants to terminate; Echo data back to client theOutput.comData="BYE."; // --- Mark the communication to be terminated --- theOutput.bExit=true; // --- Tell the server to stop listening for new clients --- ComServer.GL_listening=false; // --- Set the internal state to wait for a new client --- state=COM_STATUS_WAITING; // --- Return Data object to be sent to the client --- returntheOutput; } } if(state==COM_STATUS_WAITING) { // --- Send ready Message to the Client --- theOutput.comData="Ready:"; // --- Set the internal state ready; and wait for TerminalId --- state=COM_STATUS_WAITING_FOR_TERMINALID; } elseif(state==COM_STATUS_WAITING_FOR_TERMINALID) { intiRet; // --- Get the Terminal ID --- sTermId=theInput.comData; // --- Call 'BACK-END' modules ... --- mqTe.... ... // --- Send ready Message with the Server Version to the Client --- theOutput.comData="Ready;Server Version 1.0:"; // --- Set the internal state raedy; and wait for TerminalId --- state=COM_STATUS_READY_SENT; } elseif(state==COM_STATUS_READY_SENT) { intiRet; StringsCommand=theInput.comData; // --- Call 'BACK-END' modules ... ... /* ** --- Check if we should get Response data --- */ if(theInput.iRet==COM_DATA.NOWAIT_FOR_RESPONSE){ // -- Set the Output Value --- theOutput.iRet=iRet; theOutput.comData=""; } else{ // --- Call 'BACK-END' modules --- mqTe.... // --- Set the Output Value --- theOutput.comData=mqTe.sResponseBuffer; theOutput.iRet=iRet; } } returntheOutput; }// --- End of Method processInput() --- }// --- End of ComProtocol Class Definition --- ----
The Data object that goes through the network
[edit | edit source ]- COM_DATA
- is data structure class that is transmitted through the network. The class contains only data.
/** * COM_DATA data structure */ publicclass COM_DATAimplementsSerializable { publicStringcomData; publicbooleanbExit; publicintiRet; /** * --- Constants values can be passed in in iRet to the Server --- */ staticfinalintWAIT_FOR_RESPONSE=0; staticfinalintNOWAIT_FOR_RESPONSE=1; /** * Initialize the data structure */ publicCOM_DATA() { comData=""; bExit=false; iRet=0; }// -- End of COM_DATA() Constructor -- /** * Copy over it contents */ publicvoidcopy(COM_DATAtSrc) { this.comData=tSrc.comData; this.bExit=tSrc.bExit; this.iRet=tSrc.iRet; return; } }// -- End of COM_DATA class --
Create the Client
[edit | edit source ]A client code for a server/service is usually an API that a user application uses to interface to the server. With the help of a client API the user application does not have to know how to connect to the server to get services.
- ComClient
- This class is the client API. The application is using this class to communicate with the server.
The following is the client class for the above server:
publicclass ComClient { privateSocketcomSocket; privateObjectOutputStreamoOut; privateObjectInputStreamoIn; privatebooleanIsItOpen=false; /** * --- Open Socket --- */ publicvoidopenCom(StringsServerName, intiPortNumber)throwsUnknownHostException, IOException { try{ // --- Open Socket for communication --- comSocket=newSocket(sServerName,iPortNumber); // --- Get Stream to write request to the Server --- oOut=newObjectOutputStream(comSocket.getOutputStream()); // --- Get Stream// to read from the Server oIn=newObjectInputStream(comSocket.getInputStream()); // --- Set internal Member variable that the Communication opened --- IsItOpen=true; }catch(java.net.UnknownHostExceptione){ System.err.println("(openCom:)Don't know about host: "+sServerName); IsItOpen=false; throw(e); }catch(java.io.IOExceptione){ System.err.println("(openCom:)Couldn't get I/O for the connection to: "+sServerName); IsItOpen=false; throw(e); } } /** * --- Check if Socket is open --- */ publicbooleanisItOpen() { returnIsItOpen; } /** * --- Get data string from the Server --- */ publicvoidgetServerData(COM_DATAtServData)throwsIOException { // --- Initialize Variables --- tServData.comData=""; // --- Get the Response from the Server --- try{ tServData.copy((COM_DATA)oIn.readObject()); } catch(ClassNotFoundExceptione){ System.out.println("Class Not Found"); } System.out.println("Server: "+tServData.comData); if(tServData.comData.equals("BYE.")) { tServData.bExit=true; } return; } /** * --- Send data to the Server --- */ publicvoidsendDataToServer(COM_DATAtServData)throwsIOException { // --- Send the data string --- System.out.println("Send: "+tServData.comData); oOut.writeObject(tServData); return; } /** * --- Close Socket --- */ publicvoidcloseCom()throwsIOException { oOut.close(); oIn.close(); comSocket.close(); IsItOpen=false; } }
- getServerData( COM_DATA tServData )
- This method reads the data from the server and copies the values to
tServData
object. - sendDataToServer( COM_DATA tServData )
- This method sends the
tServData
object through the network to the server. - oIn.readObject()
- This method returns the data object sent by the server.
- oOut.writeObject( tServData )
- This method sends the data object to the server.
To do:
Add some exercises like the ones in Variables