0

With much efforts, I was finally able to build a simple HTTPS sample server implemented in Java, as shown below. It accepts client connections and sends back a piece of text about the socket information. So I have a working server sample so far; neat and tidy. How I can make it a bi-directional connection, in such a way that client be able to send/receive information as well, in an interactive mode? How should I implement the steps for going back and forward?

Basically I want a form like this to be displayed at the browser after connecting to the server (that is easy; like now, I will send the text corresponding to the form's html code). But I need the client to send the filled-out data back to the server. Server will do some process with these raw data, and return the result back to be shown at the client.

PS: Don't forget to create a keystore certificate and provide the info below if you want to test the program.

sample client

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
public class HttpsEchoer {
   public static void main(String[] args) {
      String ksName = "myks.jks";
      char ksPass[] = "mypass".toCharArray();
      char ctPass[] = "mypass".toCharArray();
      try {
         KeyStore ks = KeyStore.getInstance("JKS");
         ks.load(new FileInputStream(ksName), ksPass);
         KeyManagerFactory kmf = 
         KeyManagerFactory.getInstance("SunX509");
         kmf.init(ks, ctPass);
         SSLContext sc = SSLContext.getInstance("TLS");
         sc.init(kmf.getKeyManagers(), null, null);
         SSLServerSocketFactory ssf = sc.getServerSocketFactory();
         SSLServerSocket s 
            = (SSLServerSocket) ssf.createServerSocket(8888);
         System.out.println("Server started:");
         printServerSocketInfo(s);
         // Listening to the port
         int count = 0;
         while (true) {
            SSLSocket c = (SSLSocket) s.accept();
            // Someone is calling this server
            count++;
            System.out.println("Connection #: "+count);
            printSocketInfo(c);
            BufferedWriter w = new BufferedWriter(
               new OutputStreamWriter(c.getOutputStream()));
            BufferedReader r = new BufferedReader(
               new InputStreamReader(c.getInputStream()));
            String m = r.readLine();
//            System.out.println(m);
            if (m!=null) {
               // We have a real data connection
               w.write("HTTP/1.1 200 OK");
               w.newLine();
               w.write("Content-Type: text/html");
               w.newLine();
               w.newLine();
               w.write("<html><body><pre>");
               w.newLine();
               w.write("Connection #: "+count);
               w.newLine();
               w.newLine();
               w.write(m);
               w.newLine();
               while ((m=r.readLine())!= null) {
                  if (m.length()==0) break; // End of a GET call
                  w.write(m);
                  w.newLine();
               }
               w.write("</pre></body></html>");
               w.newLine();
               w.flush();
            }     
            w.close();
            r.close();
            c.close();
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
   private static void printSocketInfo(SSLSocket s) {
      System.out.println("Server socket class: "+s.getClass());
      System.out.println("   Remote address = "
         +s.getInetAddress().toString());
      System.out.println("   Remote port = "
         +s.getPort());
      System.out.println("   Local socket address = "
         +s.getLocalSocketAddress().toString());
      System.out.println("   Local address = "
         +s.getLocalAddress().toString());
      System.out.println("   Local port = "
         +s.getLocalPort());
   }
   private static void printServerSocketInfo(SSLServerSocket s) {
      System.out.println("Server socket class: "+s.getClass());
      System.out.println("   Socker address = "
         +s.getInetAddress().toString());
      System.out.println("   Socker port = "
         +s.getLocalPort());
      System.out.println("   Need client authentication = "
         +s.getNeedClientAuth());
      System.out.println("   Want client authentication = "
         +s.getWantClientAuth());
      System.out.println("   Use client mode = "
         +s.getUseClientMode());
   } 
}
Tina J
  • 4,983
  • 13
  • 59
  • 125

2 Answers2

1

Your Form should also contain a <BUTTON type = "submit"...> for sending the filled-in form, and the <FORM action="http://somesite..." method="post"> lets you determine where and how. The browser handles the client side (except for validating - you'd need some JavaScript code or equivalent).

The HTML 4 or 5 spec from http://www.w3.org/ contains lots of examples.

laune
  • 31,114
  • 3
  • 29
  • 42
  • One thing I'm not sure of: So basically the server should send the html text corresponding to the form, then the client fills it out and sends back the data to the server (can be JSON?). Then the server sends back the results in a simple HTML form or JSON to be mixed with client's AJAX? Any suggestions for the steps? – Tina J Jun 12 '14 at 18:00
  • Why do you want JSON? It'll have to be constructed with some client-side scripting (see the process.php in the other answer). A simple query string can be parsed quite easily, see for instance http://stackoverflow.com/questions/13592236/parse-the-uri-string-into-name-value-collection-in-java. The server program can then send another HTML, with or without another form, and so on. - You won't need AJAX for a simple form and query dialog. - OTOH, you can dig into scripting, JavaScript or whatever, and have some fun. – laune Jun 12 '14 at 19:24
1

You may need to make the server send the response in the form of a JSON string or similar, so that the client receives that, parses the result, and displays information accordingly. This is a sample I did to receive the response of a server (in the form of a JSON string) and then prints the result (I'm too lazy to translate it to english):

package com.arielnmz;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

import com.google.gson.Gson;

public class JavaHttpRequestJSON {
    public static void main(String[] args) throws Exception {
        while (true) {
            new JavaHttpRequestJSON().testGet(new java.util.Random().nextInt());
            Thread.sleep(2000);
        }
    }
    private void testGet(int valor) throws Exception {

        // Crear URL
        URL url = new URL("http://localhost/http_req_test/server_script_json.php");

        // Establecer conexión
        URLConnection conexion = url.openConnection();

        // Enviaremos información
        conexion.setDoOutput(true);

        // Recibiremos respuesta
        conexion.setDoInput(true);

        // Establecer timeouts
        conexion.setConnectTimeout(5000);
        conexion.setReadTimeout(5000);

        // Usar caches: NO
        conexion.setUseCaches(false);
        conexion.setDefaultUseCaches(false);

        // Le decimos al servidor qué y cómo estamos enviando
        conexion.setRequestProperty("Content-Type", "application/json");

        // Creamos una instancia de nuestro "codificador" JSON
        String json;
        Gson gson = new Gson();

        // Creamos un objeto y lo codificamos como JSON
//      Map<String, String> map = new HashMap<String, String>(); 
//      map.put("valor", Integer.toString( num ) );
        ObjetoEnvio objetoEnvio = new ObjetoEnvio();
        objetoEnvio.setValor(valor);

        json = gson.toJson(objetoEnvio);

        System.out.println("Objeto en JSON: "+json+" / valor enviado "+objetoEnvio.getValor());

        DataOutputStream os = new DataOutputStream(conexion.getOutputStream());
        os.writeBytes(json);
        os.close();

        StringBuffer respuesta = new StringBuffer();

        BufferedReader in = new BufferedReader( 
            new InputStreamReader( conexion.getInputStream() )
        );

        String linea;
        while ((linea = in.readLine()) != null) {
            respuesta.append(linea);
        }
        in.close();

        ObjetoRespuesta respuesta_json = gson.fromJson(respuesta.toString(), ObjetoRespuesta.class);

//      System.out.println(respuesta.toString());
        System.out.println(respuesta_json.getMensaje());
        System.out.println("Conexión finalizada");
    }

    private class ObjetoEnvio {
        private int valor;
        public void setValor(int valor) {
            this.valor = valor;
        }
        public int getValor() {
            return valor;
        }
    }

    private class ObjetoRespuesta {
        private String mensaje;
        public String getMensaje() { return mensaje; }
    }
}

Update:

This answer is based on this approach:

  1. I send an HTTP request to the server and it delivers a response in the form of an stream of data (e.g. utf8 encoded chars) that my webkit widget renders as HTML.
  2. I fill the HTML form and submit the data as an url-encoded string via the action and method properties as a normal HTML form would do. E.g:
    • <form method="POST" action="process.php">
  3. The server receives the data and processes it, and it returns a stream of characters again, but this time those characters don't represent an HTML structure but rather a JSON-encoded object. E.g:
    • "{ 'response' : 1 }";
  4. The client now receives that string but instead of trying to represent those characters as an HTML structure, you can parse them into a Java object that you can now use however you want.
arielnmz
  • 8,354
  • 9
  • 38
  • 66
  • One thing I'm not sure of: So basically the server should send the html text corresponding to the form, then the client fills it out and sends back the data to the server (can be JSON?). Then the server sends back the results in a simple HTML form or JSON to be mixed with client's AJAX? Any suggestions for the steps? – Tina J Jun 12 '14 at 18:02
  • That may be one approach. See my updated answer for the approach I used. With your approach you just submit the form in step `2` as a `JSON` object rather than an `URL` encoded string. Not much different, it can work too. – arielnmz Jun 12 '14 at 18:17