Choice of Server: Socket or Servlet

Hey experts,

This is a decision making question, I want to write code for a server (in Java) that accepts connections with more than one client, and it would receive a very long string of data from one of these clients, and then forwards it to other connected client(s) specified by the sender client; the server should also return the status of certain clients upon the request of one client, i.e. if they are connected or no.

Since connecting to a Web server is easy (done by connecting to its specified IP address), I thought of writing the server code using a servlet (which is  a web server), but then it turns out that a servlet has certain limitations since the DoGet, and the DoPost methods are run in a single thread, and thus only one client can connect at a time, and thus when the servlet is processing a request of one client in its DoGet method for example, other client(s) must wait until the servlet finishes processing the current request for their own requests to be processed, so the option of forwarding the long string of data from one client to another doesn't seem straight forward in a servlet. However, a Socket Server (i.e. a regular server that is running on a certain port - maybe in a network - in which clients can connect to by accepting a socket connection & data is transferred via this socket) seems easier for multiple client connections because it is multi-threaded, so the option of forwarding seems a bit easier; on the other hand, using this server as a server on the Web seems more difficult (personally, I have no idea if this possible); therefore I am posing this question for the experts to help me in chosing the server's type based on the duties that my server will do (which is forwarding long strings of data from one client to other(s) - mentioned above).

Just for mind refreshing purposes, I will post some open source example code for a Socket Server & a Servlet to aid us in discussing the server choice (THESE HAVE NOTHING TO DO WITH MY OWN SERVER WHICH WILL BE COMPLETELY DIFFERENT):

*****************************************************************************
Socket Server Example:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.ServerSocket;

import java.sql.*;

public class SkillsServer {

  private int port = 1927;

  private ServerSocket serverSocket;

  static final String dbURL =
    "jdbc:mysql://localhost/j2mebook?" +
    "user=j2meapps&password=bigsecret";

  public SkillsServer() throws ClassNotFoundException {
    Class.forName("org.gjt.mm.mysql.Driver");
  }

  public void acceptConnections() {

    try {
      serverSocket = new ServerSocket(port);
    }
    catch (IOException e) {
      System.err.println("ServerSocket instantiation failure");
      e.printStackTrace();
      System.exit(0);
    }

    while (true) {
      try {
        Socket newConnection = serverSocket.accept();
        System.out.println("accepted connection");
        ServerThread st = new ServerThread(newConnection);
        new Thread(st).start();
      }
      catch (IOException ioe) {
        System.err.println("server accept failed");
      }
    }
  }
   
  public static void main(String args[]) {

    SkillsServer server = null;
    try {
      server = new SkillsServer();
    }
    catch (ClassNotFoundException e) {
      System.out.println("unable to load JDBC driver");
      e.printStackTrace();
      System.exit(1);
    }

    server.acceptConnections();
  }

  class ServerThread implements Runnable {

    private Socket socket;
    private DataInputStream datain;
    private DataOutputStream dataout;

    public ServerThread(Socket socket) {
      this.socket = socket;
    }

    public void run() {
      try {
        datain = new DataInputStream(new BufferedInputStream
          (socket.getInputStream()));
        dataout = new DataOutputStream(new BufferedOutputStream
          (socket.getOutputStream()));
      }
      catch (IOException e) {
        return;
      }
      byte[] ba = new byte[6];
      boolean conversationActive = true;
      while(conversationActive) {
        String skill = null;
        try {
          datain.read(ba,0,6);
          skill = new String(ba);
          if ((skill.length() == 1) && 
              (skill.toUpperCase().charAt(0) == 'Q')) {
            conversationActive = false;
          }
          else {
            System.out.println("requested skill = " + skill);
            String names = getNames(skill);
            System.out.println("names: " + names);
            System.out.println("writing " + names.length() + " bytes");
            dataout.write(names.getBytes(),0,names.length());
            dataout.write("\n".getBytes(),0,1);
            dataout.flush();
          }
        }
        catch (IOException ioe) {
          conversationActive = false;
        }
      }
      try {
        System.out.println("closing socket");
        datain.close();
        dataout.close();
        socket.close();
      }
      catch (IOException e) {
      }
    }

    private String getNames(String skill) {
      String result = "None available";
      Connection conn = null;
      try {
        conn = DriverManager.getConnection(dbURL);

        Statement stmt = conn.createStatement();
        String query = "SELECT lastname, firstname " +
                       "FROM skills " + "WHERE skill = " +
                       "'" + skill.trim() + "'" +
                       " ORDER BY lastname";
        System.out.println("query = " + query);
        ResultSet rs = stmt.executeQuery(query);
        StringBuffer sb = new StringBuffer();
        while (rs.next()) {
          sb.append(rs.getString(1));
          sb.append(", ");
          sb.append(rs.getString(2));
          sb.append('$');
        }
        result = sb.toString();
      }
      catch (SQLException e) {
        System.out.println(e.getMessage());
        result = "server error";
      }
      finally {
        if (conn != null) {
          try {
            conn.close();
          }
          catch (SQLException e) {
          }
        }
      }
      return result;
    }
  }
}


*******************************************************************

Servlet Example:

import java.io.*;
import java.text.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import java.sql.*;

public class SkillsServlet extends HttpServlet {

  static final String dbURL =
    "jdbc:mysql://localhost/j2mebook?" +
    "user=j2meapps&password=bigsecret";

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
      throws IOException, ServletException {
   
    Connection conn = null;

    String nextJSP = null;

    try {
      Class.forName("org.gjt.mm.mysql.Driver");
    }
    catch (ClassNotFoundException e) {
      throw new ServletException("Unable to load JDBC driver");
    }

    try {
      String[] skills = request.getParameterValues("skills");

      conn = DriverManager.getConnection(dbURL);

      Statement stmt = conn.createStatement();

      String baseQuery = "SELECT lastname, firstname " +
                     "FROM skills " + "WHERE skill IN (";

      StringBuffer sb = new StringBuffer(baseQuery);
      for (int i = 0; i < skills.length; ++i) {
        sb.append('\'');
        sb.append(skills[i]);
        sb.append('\'');
        if ((i +1) < skills.length) {
          sb.append(",");
        }
      }
      sb.append(") ORDER BY lastname");
      String query = sb.toString();

      ResultSet rs = stmt.executeQuery(query);
      nextJSP = "/ReportCandidates.jsp";
      sb = new StringBuffer();
      while (rs.next()) {
        sb.append(rs.getString(1));
        sb.append(',');
        sb.append(rs.getString(2));
        sb.append('\n');
      }
      if (sb.length() > 0) {
        request.setAttribute("candidateList",sb.toString());
      }
      else {
        nextJSP = "/NoCandidates.jsp";
      }
      conn.close();
      ServletConfig config = getServletConfig();
      ServletContext context = config.getServletContext();
      RequestDispatcher rd = context.getRequestDispatcher(nextJSP);
      rd.forward(request, response);
    }
    catch (SQLException e) {
      throw new ServletException("SQL call failed");
    }
    catch (Exception e) {
      throw new ServletException(e.getMessage());
    }
    finally {
      if (conn != null) {
        try {
          conn.close();
        }
        catch (SQLException e) {
          throw new ServletException("connection close failed");
        }
      }
    }
  }
}
LVL 3
mte01Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jv-stCommented:
Did you try the servlet approach? If the server is single threading requests to a servlet that would be surprising (to me).
mte01Author Commented:
>>Did you try the servlet approach?

Yes, I did with 3 clients making requests (just for testing purposes), apparently they were concurrent with relatively large timestamps between them in which I made a conclusion - which may not be very accurate - that it is single-threaded; what supported my conclusion is that there is no class that implements Runnable - no run method....etc. I may not be very knowledgeable about servlets, so please tell me if I say something that doesn't seem accurate.
mte01Author Commented:
>>jv-st

If you suggest the servlet, please explain how do you think the forwarding mechanism can be done from one sender client to a receiver client??
Introduction to R

R is considered the predominant language for data scientist and statisticians. Learn how to use R for your own data science projects.

jv-stCommented:
How do you want to forward from the server to the other clients? Synchronously (push), or store and forward when other clients ask for it? If synchronously, then maybe persistent HTTP connections? Or the server (either servlet or a socket server) would have to open socket connections to each client (which would mean the clients would have to be listening for incoming connections. If it was a servlet doing that, it would want to spawn threads to send to each client, but spawning multiple threads from a servlet might be problematic.
jv-stCommented:
re servlets, there is an option to make them single threaded but afaik they each runin their own thread by default
jv-stCommented:
ie each request to a given servlet should run in it's own thread.
mte01Author Commented:
1->>How do you want to forward from the server to the other clients?

Synchronously (Push) since the forwarding would be done only for client(s) that are already connected to the servlet.

2- What do you mean by persistent HTTP connections??

3->>spawning multiple threads from a servlet might be problematic

From this I can see that using a Socket Server is better, unless this spawning thing is only done in the "store and forward" case
jv-stCommented:
Http is basically a request-response model, ie client opens a connection to http server, sends request to servlet, servlet sends response to client, connection is closed. So your clients would not be connected continuously to the servlet.

In Persistent HTTP, the connection stays open and the server can send data as available, such as streaming audio. So you could look into Persistent HTTP. Sometimes you have to stay with HTTP for reasons like going through firewalls.

With socket server, there would seem to be 2 options. each client is 'connected' to server, by one connection. But you will have a problem when 2 clients are sending at the same time, you have to somehow multiplex the connection. The other option would be that when the server received a request it would start a fresh connection to each client. In this case the clients would themselves would be acting as servers when the server contacted them. This way there could be more than one download to a given client going on at the same time. But that option changes your requirement of recognizing who to send to by whether they have an open connection. (but with servlets, since connection is not normally persistent, you dont know that anyway).
mte01Author Commented:
>>jv-st

I see.....so as it seems to me going in java code through persistent HTTP doesn't seem that easy, so I think it would be better for me to go with a socket server (Dealing with the problem of multiplexing the connection can be discussed later, but I can see from now that there can be many methodologies to solve it). If you agree with me on using the Socket Server, do you have any idea on how to actually deploy this solution??, for I will want to connect to it later using the Web, but in the server code the connection is done by specifying only the port (of course here it's to the localhost), and do you suggest I would ask a question in the Networking area regarding this problem??
jv-stCommented:
A usual reason to try to stick to HTTP is if there were firewall issues (ie with a socket server approach you will be using other ports and have to be sure that those ports aren't blocked. If that's not an issue, then score 1 for Socket server.

Another issue is being thin client. With the socket server approach you'll need to have java running on client. So you would have to install the java client. If thats not a problem, score another for socket server. (If it is an issue, you should be able to implement the client side as a java applet in a web page).

As far as multiplexing one connection you dont want that. It could be done with enough work but it would be way easier to just open and close separate connections for each download.

Re persistent HTTP not being easy, I agree. So from the data you have given so far I would agree with you that Socket server is the answer.

As for deploying, the java client would have to be installed on client. Or maybe it is something like this: each client connects to web server. web server responds with an applet which is the java client program. The applet could open a connection back to the socket server. This connection a) tells the socket server who is online, and b) is used as the upload channel. The applet also listens on another port for download requests the socket server.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mte01Author Commented:
An important thing that I didn't mention here is that the client is a mobile phone (but I was trying to see first how would the problem would be solved with a regular client PC - that's why I didn't mention that important point)

1) No firewall issues ==> Socket Server

2) Java Run Time Environment is for sure installed on the client mobile phone ==> Socket Server

3) Persistent HTTP is not easy ==> Socket Server

As I have looked right now at J2ME code in which a client mobile connects to this Socket Server, I reassured myself that the connection with this server via the web is easy and I will post a question in a sub topic area of the Networking area to have more details regarding this matter.

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java EE

From novice to tech pro — start learning today.