Construir un Servidor Web en Java

Creación de nuestro propio servidor Web

Vamos a escribir un pequeño programa para demostrar las capacidades de MultiThread de Java así como exponer de un modo sencillo otras características como son la creación de aplicaciones cliente-servidor con sockets, la escritura en Streams y el control de excepciones, etc …

Esqueleto básico

Primero vamos a escribir el esqueleto de nuestro programa para no tener que ir repitiendo grandes trozo de código. Este esqueleto podeis observar que esta vacio y no es muy funcional, aunque ya lo iremos rellenando a medida que haga falta.

Lo más importante es el concepto que vamos a tener una función que se llama arranca, dentro de una clase que se habrá encargado de leer los parámetros que le hayan pasado desde la línea de comandos y que disponemos de un método para centralizar los logs…. lo demás ya veremos

 

 

Bueno, lo primero que tenemos que hacer, es quedarnos a la espera en un puerto, creando un Socket de servidor.

Cuando un navegador nos envie una pertición, la procesamos y mostramos por pantalla

 

Si desde un navegador, realizamos una petición a este estilo

En nuetro log veremos

Mensaje: Arrancamos nuestro servidor
Mensaje: Quedamos a la espera de conexion
Mensaje: Procesamos conexion
Mensaje: –GET / HTTP/1.0
Mensaje: –Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Mensaje: –Accept-Language: es
Mensaje: –User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Mensaje: –Host: localhost:90
Mensaje: –Connection: Keep-Alive
Mensaje: —

Si dejamos tal cual este programa, nos puede ser muy útil en ciertas circunstancias… por ejemplo, como hemos visto en el caso anterior, para comprobar que manda nuestro navegador a un sitio Web (para depurar problemas)

Por ejemplo …. quiero saber que información arrastra mi navegador cuando se conecta a un phpNuke (gestor de presentación de contenidos gratuito creado en php).

Ataco a mi máquina donde tengo phpNuke

Luego me conecto a mi misma máquina al puerto de mi programa …

Mensaje: –GET / HTTP/1.0
Mensaje: –Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Mensaje: –Accept-Language: es
Mensaje: –User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Mensaje: –Host: localhost:90
Mensaje: –Connection: Keep-Alive
Mensaje: –Cookie: ASPSESSIONIDCCTBSQBA=GBDFCHBDFKMNDPBBDFPJIMIO
Mensaje: —

Y sorpresa …. compruebo que me genera un cookie ……… para mantener la sensación de sesión ……

(a algunos seguro que se les ha hecho los ojos chirivitas ……por el posible problema de seguridad cuando navegais de un Web a otro ….. ) seguro a partir de ahora … cuando esteis logados en un servidor ….. pinchareis al botón “cerrar sesión”  antes de navegar por otros Webs …..

 

Dotar de funcionalidad nuestro servidor Web

No se si ya habeís tenido la percepción de que  nuestro programa tiene algunas deficiencias:

  • Primero … que no vemos que nos pide el usuario y no se lo enviamos ……

  • Segundo …. nuestro programa solo sirve una petición y se apaga …..

  • Tercero …. como resolveríamos la situación (normal) de que más de un usuario nos realizase peticiones simultaneas …..

He aquí donde ya identificamos ciertas necesidades que vamos a tratar de resolver.

Multiproceso

Vamos por cachos …. primero empezamos por los problemas más graves…. vamos a hacer que nuestra aplicación sea multi-hilo (multi-thread) de tal modo que vamos a crear una nueva clase … que derive de Thread y que sea capaz de atender cada petición en paralelo que recibamos

Modificamos la clase principal:

Ahora la clase auxiliar

Si analizamos la respuesta de nuestro Web ante varias peticiones:

——————–Configuration: C:\java\jakarta-tomcat-4.1.12\common\lib roberto——————–
Mensaje: Arrancamos nuestro servidor
Mensaje: Quedamos a la espera de conexion
Thread[Thread-1,4,main] – Procesamos conexion
Thread[Thread-1,4,main] – –GET / HTTP/1.0
Thread[Thread-1,4,main] – –Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Thread[Thread-1,4,main] – –Accept-Language: es
Thread[Thread-1,4,main] – –User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Thread[Thread-1,4,main] – –Host: localhost:90
Thread[Thread-1,4,main] – –Connection: Keep-Alive
Thread[Thread-1,4,main] – –Cookie: ASPSESSIONIDCCTBSQBA=GBDFCHBDFKMNDPBBDFPJIMIO
Thread[Thread-1,4,main] – —
Thread[Thread-1,4,main] – Error en servidor
java.net.SocketException: Connection reset
Thread[Thread-1,4,main] – Hemos terminado
Thread[Thread-2,4,main] – Procesamos conexion
Thread[Thread-2,4,main] – –GET /?a=1 HTTP/1.0
Thread[Thread-2,4,main] – –Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Thread[Thread-2,4,main] – –Accept-Language: es
Thread[Thread-2,4,main] – –User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Thread[Thread-2,4,main] – –Host: localhost:90
Thread[Thread-2,4,main] – –Connection: Keep-Alive
Thread[Thread-2,4,main] – –Cookie: ASPSESSIONIDCCTBSQBA=GBDFCHBDFKMNDPBBDFPJIMIO
Thread[Thread-2,4,main] – —
Thread[Thread-2,4,main] – Error en servidor
java.net.SocketException: Connection reset
Thread[Thread-2,4,main] – Hemos terminado
Thread[Thread-3,4,main] – Procesamos conexion
Thread[Thread-3,4,main] – –GET /?a=3 HTTP/1.0
Thread[Thread-3,4,main] – –Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Thread[Thread-3,4,main] – –Accept-Language: es
Thread[Thread-3,4,main] – –User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Thread[Thread-3,4,main] – –Host: localhost:90
Thread[Thread-3,4,main] – –Connection: Keep-Alive
Thread[Thread-3,4,main] – –Cookie: ASPSESSIONIDCCTBSQBA=GBDFCHBDFKMNDPBBDFPJIMIO
Thread[Thread-3,4,main] – —

Así, es posible que no tengamos la percepción de multi-hilo. Vamos a poner un retardo en cada petición para ver como se intercalan en el log

Modificamos el programa:

Vemos el Log donde comprobamos la concurrencia ….. 

——————–Configuration: C:\java\jakarta-tomcat-4.1.12\common\lib roberto——————–
Mensaje: Arrancamos nuestro servidor
Mensaje: Quedamos a la espera de conexion
Thread[Thread-1,4,main] – Procesamos conexion
Thread[Thread-1,4,main] – –GET /?a=1 HTTP/1.0
Thread[Thread-1,4,main] – –Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*

Thread[Thread-1,4,main] – –Accept-Language: es
Thread[Thread-1,4,main] – –User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Thread[Thread-2,4,main] – Procesamos conexion
Thread[Thread-1,4,main] – –Host: localhost:90
Thread[Thread-2,4,main] – –GET /?a=2 HTTP/1.0
Thread[Thread-1,4,main] – –Connection: Keep-Alive
Thread[Thread-2,4,main] – –Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Thread[Thread-1,4,main] – –Cookie: ASPSESSIONIDCCTBSQBA=GBDFCHBDFKMNDPBBDFPJIMIO
Thread[Thread-2,4,main] – –Accept-Language: es
Thread[Thread-1,4,main] – —
Thread[Thread-1,4,main] – Error en servidor
java.net.SocketException: Connection reset
Thread[Thread-1,4,main] – Hemos terminado

Thread[Thread-2,4,main] – –User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Thread[Thread-2,4,main] – –Host: localhost:90
Thread[Thread-2,4,main] – –Connection: Keep-Alive
Thread[Thread-2,4,main] – –Cookie: ASPSESSIONIDCCTBSQBA=GBDFCHBDFKMNDPBBDFPJIMIO
Thread[Thread-2,4,main] – —

Retornar una respuesta

Ahora vamos a incluir la funcionalidad para retornar la página que no solicita el usuario.

Y añadimos el nuevo método

 

Puede descargarse el códigofuente aquí

Sobre el Autor ..