<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title><![CDATA[Latest posts for the topic "Building a simple socket based HTTP server"]]></title>
		<link>http://forums.hotjoe.com/posts/list/27.page</link>
		<description><![CDATA[Latest messages posted in the topic "Building a simple socket based HTTP server"]]></description>
		<generator>JForum - http://www.jforum.net</generator>
			<item>
				<title>Building a simple socket based HTTP server</title>
				<description><![CDATA[ I'd like to create an article on building a very simple HTTP server.  There are other tutorials out there but I'll try my shot at it too.  It seems that sockets are a common discussion topic.  As part of this the first post will be about the requirements that I'm going to try to satisfy.<br /> <br /> The first and most important thing is that the purpose of this is to provide a framework for learning.  It is not to produce a production quality web server like Apache or Tomcat.  While the code will be high quality I may take shortcuts or leave some features out in the interest of time or clarity.  I will try to point out where I feel that a shortcut or non-enterprise design has been used.  A side effect of this requirement is we will not use anything except for the classes available in 1.4 J2SE.  There are many excellent libraries available for networking.  But this is meant to be a learning program.  By doing it "by hand" one time I find that you learn significantly more than jumping straight to a thrid party library.<br /> <br /> Which leads to the second requirement.  I'm going to limit the initial scope to only handle the HTTP GET command.  This is the most commonly used HTTP command.  However, this means that the first version of the software will not be able to handle form processing.  As time permits I will also include the HTTP POST command.<br /> <br /> The server should comply with [url=http://www.w3.org/Protocols/rfc2616/rfc2616.html]RFC 2616[/url] in the GET area where possible.  Where it isn't possible it should work well with any HTTP client.  While the majority of the HTTP clients are browsers the server should work equally well with programs such as [url=http://www.gnu.org/software/wget/wget.html]wget[/url] where there is much more limited user interaction.<br /> <br /> Lastly, the code will be developed in a Java [b]1.4[/b] environment.  While Java 1.5/5.0 is the current release the intention is to allow the most number of people to benefit from this.  1.5 is still in limited use outside of schools.  From what I can see a significant number of people are still using 1.4.  Where something might be easier in 1.5 we will try to point that out.<br /> <br /> If you'd like to see other requirements please feel free to post it in this thread.  We can discuss what else may be useful and add it to the requirements as time permits.<br /> ]]></description>
				<guid isPermaLink="true">http://forums.hotjoe.com/posts/preList/62/144.page</guid>
				<link>http://forums.hotjoe.com/posts/preList/62/144.page</link>
				<pubDate><![CDATA[Fri, 2 Dec 2005 11:39:01]]> GMT</pubDate>
				<author><![CDATA[ stdunbar]]></author>
			</item>
			<item>
				<title>Re:Building a simple socket based HTTP server</title>
				<description><![CDATA[ The core of the server will be based on [url=http://java.sun.com/j2se/1.4.2/docs/api/java/net/ServerSocket.html]ServerSocket[/url].  This is the base server side class when using TCP sockets.<br /> <br /> Let's look at the some of the methods that I'll be using (quotes from the Javadoc):<br /> <br /> [quote]public ServerSocket(int port) throws IOException<br /> <br /> Creates a server socket, bound to the specified port.[/quote]<br /> <br /> This is the basis of our server.  We'll create a ServerSocket that, in the Berkeley sockets (regular C sockets on most Unix systems) terminology does a bind() to a particular port.  What this means is that once you call this (and assuming that no exceptions get thrown) there will be a socket ready to accept connections on the port we specify.   So lets start with a little code to test this:<br /> <br /> [code]<br /> import java.net.ServerSocket;<br /> import java.net.Socket;<br /> <br /> <br /> public class SimpleHTTPServer<br /> {<br />     private ServerSocket serverSocket = null;<br /> <br />     public void runServer( int port )<br />     {<br />         try<br />         {<br /> // create a new ServerSocket and bind it to the specified port<br />             serverSocket = new ServerSocket( port );<br /> // now do the same thing as a listen().  this method will block until a client connects to us.<br />             Socket nextClientSocket = serverSocket.accept();<br /> // print a little bit out about the client<br />             System.out.println( "got a connection from " + nextClientSocket.getInetAddress().toString() );<br /> // close the socket for now as we're just testing<br />             nextClientSocket.close();<br />         }<br />         catch( Exception e )<br />         {<br />             System.err.println( "cannot create new server socket on port " + port );<br />             e.printStackTrace( System.err );<br />             return;<br />         }<br />     }<br /> <br />     public static void main( String[] argv )<br />     {<br />         int port = 0;<br /> <br />         if( argv.length != 1 )<br />         {<br />             System.err.println( "usage: java SimpleHTTPServer &lt;port&gt;" );<br />             System.exit( 1 );<br />         }<br /> <br />         try<br />         {<br />             port = Integer.parseInt( argv[0] );<br />         }<br />         catch( NumberFormatException nfe )<br />         {<br />             System.err.println( "please use a valid integer for the port" );<br />             System.exit( 1 );<br />         }<br /> <br />         SimpleHTTPServer server = new SimpleHTTPServer();<br />         server.runServer( port );<br />     }<br /> }<br /> [/code]<br /> <br /> We'll setup a real build environment in a bit but this can be compiled by hand:<br /> <br /> [code]<br /> javac SimpleHTTPServer.java<br /> [/code]<br /> <br /> and run with<br /> <br /> [code]<br /> java SimpleHTTPServer 1234<br /> [/code]<br /> <br /> You can select anything you want for the port number as long as two conditions are satisfied.  The first is that, on Unix and Linux the default configuration only allows you to bind to a port number of 1024 and higher.  If you try to bind to something less you'll get an exception like:<br /> <br /> [code]<br /> [httpserver]$ java SimpleHTTPServer 123<br /> cannot create new server socket on port 123<br /> java.net.BindException: Permission denied<br />         at java.net.PlainSocketImpl.socketBind(Native Method)<br />         at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:331)<br />         at java.net.ServerSocket.bind(ServerSocket.java:318)<br />         at java.net.ServerSocket.&lt;init&gt;(ServerSocket.java:185)<br />         at java.net.ServerSocket.&lt;init&gt;(ServerSocket.java:97)<br />         at SimpleHTTPServer.runServer(SimpleHTTPServer.java:14)<br />         at SimpleHTTPServer.main(SimpleHTTPServer.java:51)<br /> [/code]<br /> <br /> Secondly, if you try to use a port that is already in use you'll get something like:<br /> <br /> [code]<br /> [httpserver]$ java SimpleHTTPServer 8009<br /> cannot create new server socket on port 8009<br /> java.net.BindException: Address already in use<br />         at java.net.PlainSocketImpl.socketBind(Native Method)<br />         at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:331)<br />         at java.net.ServerSocket.bind(ServerSocket.java:318)<br />         at java.net.ServerSocket.&lt;init&gt;(ServerSocket.java:185)<br />         at java.net.ServerSocket.&lt;init&gt;(ServerSocket.java:97)<br />         at SimpleHTTPServer.runServer(SimpleHTTPServer.java:14)<br />         at SimpleHTTPServer.main(SimpleHTTPServer.java:51)<br /> [/code]<br /> <br /> Otherwise, you can test that this works by using the telnet program.  You'll want to do something like:<br /> <br /> [code]<br /> telnet localhost 1234<br /> [/code]<br /> <br /> (assuming that you're running the client - telnet - and the server on the same machine).<br /> <br /> You will get something like:<br /> <br /> [code]<br /> [httpserver]$ java SimpleHTTPServer 1234<br /> got a connection from /127.0.0.1<br /> [/code]<br /> <br /> on the server side and:<br /> [code]<br /> [httpserver]$ telnet localhost 1234<br /> Trying 127.0.0.1...<br /> Connected to localhost.<br /> Escape character is '^]'.<br /> Connection closed by foreign host.<br /> [/code]<br /> <br /> in the telnet window.  This is exactly what we expect as the server simply closes the new socket once it is done.  Note that the exact messages may be slightly different depending on your operating system and the version of Java you're using.  These messages were generated on a Fedora Core 3 Linux system using Java version 1.4.2_08.]]></description>
				<guid isPermaLink="true">http://forums.hotjoe.com/posts/preList/62/146.page</guid>
				<link>http://forums.hotjoe.com/posts/preList/62/146.page</link>
				<pubDate><![CDATA[Fri, 2 Dec 2005 16:17:12]]> GMT</pubDate>
				<author><![CDATA[ stdunbar]]></author>
			</item>
			<item>
				<title>Looks good so far!</title>
				<description><![CDATA[ [quote]<br /> We'll setup a real build environment in a bit but this can be compiled by hand:<br /> [/quote]<br /> <br /> <img src="http://forums.hotjoe.com//images/smilies/3b63d1616c5dfcf29f8a7a031aaa7cad.gif" /> Has it been a bit yet? I'm a little curious how an experienced developer does this. I've just got a bat file that automates an ant file for me. All in all it’s just a mess of exist bat/com files mixed together into one giant intelligible mess. <br /> <br /> Looks like a good start. Instead of doing some research and answering my own question I’d figure I’d ask them here to stimulate conversation...yeah that's the ticket <img src="http://forums.hotjoe.com//images/smilies/8a80c6485cd926be453217d59a84a888.gif" /><br /> <br /> With just the ServerSocket looking accepting on a port, we don't specifically have a HTTP server right?  I was able to test it via the telnet as well as through my browser (<a class="snap_shots" href="http://localhost:1234" target="_blank" rel="nofollow">http://localhost:1234</a>)  I guess to put it another way. What makes an HTTP Server an HTTP Server over a gaming server or over a FTP server? (I realize that I’m probably butchering the networking lingo) <br /> Is the underlying setup the same for all of these? In other words, would an HTTPServer just open a ServerSocket then call a GetMethod, a FTP server would open a ServerSocket then call a doFTPHandshake method, etc.<br /> <br /> Is it even possible to look at a connection and figure out which protocol to send it on to, or would you need to open an HTTP socket, an FTP socket, and a GameProtocol socket?<br /> <br /> EDIT:  ugh...didn't mean to post a new thread. Can you move this to the HTTPServer thread or delete this post and I'll repost it? <br /> ]]></description>
				<guid isPermaLink="true">http://forums.hotjoe.com/posts/preList/62/283.page</guid>
				<link>http://forums.hotjoe.com/posts/preList/62/283.page</link>
				<pubDate><![CDATA[Tue, 20 Dec 2005 12:41:14]]> GMT</pubDate>
				<author><![CDATA[ tfecw]]></author>
			</item>
			<item>
				<title>Looks good so far!</title>
				<description><![CDATA[ [quote=tfecw]Has it been a bit yet? I'm a little curious how an experienced developer does this. I've just got a bat file that automates an ant file for me. All in all it’s just a mess of exist bat/com files mixed together into one giant intelligible mess.[/quote]<br /> <br /> Well I don't know what experienced developers do but I'll use that as a lead into my next post <img src="http://forums.hotjoe.com//images/smilies/3b63d1616c5dfcf29f8a7a031aaa7cad.gif" /><br /> <br /> [quote=tfecw]Is the underlying setup the same for all of these? In other words, would an HTTPServer just open a ServerSocket then call a GetMethod, a FTP server would open a ServerSocket then call a doFTPHandshake method, etc.<br /> [/quote]<br /> The underlying setup [b]is[/b] the same for all of them, though FTP has a bit of a strange protocol by default.  With what exists so far it could be made into an HTTP server, a chat server, a game server, an email server and so on.  HTTP follows a long line of successful character based network servers.  Basically these are servers that communicate actions via simple character interaction.<br /> <br /> [quote=tfecw]<br /> Is it even possible to look at a connection and figure out which protocol to send it on to, or would you need to open an HTTP socket, an FTP socket, and a GameProtocol socket?<br /> [/quote]<br /> By itself, no.  The socket is waiting for someone to connect to it and start a conversation.  HTTP, like many other networking services, is at the application layer of the [url=http://en.wikipedia.org/wiki/OSI_model]7 layer OSI networking model[/url].  But you can't really tell what is sitting on the port.  There are [url=http://www.iana.org/assignments/port-numbers]well known port numbers[/url] so that if you connect to, for example, port 80 then you are very likely talking to an HTTP server but there is nothing that enforces this other than a desire to work with other applications.]]></description>
				<guid isPermaLink="true">http://forums.hotjoe.com/posts/preList/62/288.page</guid>
				<link>http://forums.hotjoe.com/posts/preList/62/288.page</link>
				<pubDate><![CDATA[Wed, 21 Dec 2005 10:54:52]]> GMT</pubDate>
				<author><![CDATA[ stdunbar]]></author>
			</item>
			<item>
				<title>Re:Building a simple socket based HTTP server</title>
				<description><![CDATA[ On to the build environment!<br /> <br /> For this example we're going to use a pretty simple directory structure.  It is going to look like:<br /> <br /> [code]<br /> httpserver/<br />     src/<br />         com/<br />             hotjoe/<br />                 http/<br />                     server/<br />                         SimpleHTTPServer.java<br />     build.xml<br />     lib/<br /> [/code]<br /> <br /> So there are two things with this.  The first is that the code I posted before will now need a package declaration:<br /> <br /> [code]<br /> package com.hotjoe.http.server;<br /> <br /> import java.net.ServerSocket;<br /> import java.net.Socket;<br /> <br /> ...<br /> [/code]<br /> <br /> and we will need to create a build.xml file for [url=http://ant.apache.org/]Ant[/url].<br /> <br /> Ant is a build tool that takes care of things like making sure that if a source file (.java) has changed it recompiles the file into a new .class file.  There are many other things it can do but that is the crux of what we will be using it for.<br /> <br /> So lets create a pretty simple build.xml (the default file name that ant uses) and go through it:<br /> <br /> [code]<br /> &lt;project name="httpserver" default="main" basedir="."&gt;<br /> <br /> &lt;!-- override any of the properties in build.properties --&gt;<br />     &lt;property file="build.properties"/&gt;<br /> <br /> &lt;!-- location properties --&gt;<br />     &lt;property name="src.dir" location="src" /&gt;<br />     &lt;property name="dest.classes.dir" location="classes" /&gt;<br />     &lt;property name="dest.lib.dir" location="lib" /&gt;<br />     &lt;property name="javadoc.dir" location="javadoc" /&gt;<br /> <br /> &lt;!-- value properties --&gt;<br />     &lt;property name="dest.lib.name" value="httpserver.jar" /&gt;<br />     &lt;property name="main.class" value="com.hotjoe.http.server.SimpleHTTPServer" /&gt;<br />     &lt;property name="javadoc.package.names" value="com.hotjoe.*" /&gt;<br /> <br /> &lt;!-- compile time value properties --&gt;<br />     &lt;property name="compile.debug" value="true" /&gt;<br />     &lt;property name="compile.optimize" value="false" /&gt;<br />     &lt;property name="compile.deprecation" value="true" /&gt;<br />     &lt;property name="compile.source" value="1.4"/&gt;<br />     &lt;property name="compile.target" value="1.4"/&gt;<br /> <br /> &lt;!-- define a timestamp for the build time --&gt;<br />     &lt;tstamp&gt;<br />         &lt;format property="build.start.time" pattern="MMM dd, yyyy 'at' hh:mm:ss aa zzz" /&gt;<br />     &lt;/tstamp&gt;<br /> <br /> &lt;!-- build --&gt;<br />     &lt;target name="main" depends="compile,jar" /&gt;<br /> <br />     &lt;target name="compile" depends="checks"&gt;<br />         &lt;mkdir dir="${dest.classes.dir}"/&gt;<br />         &lt;mkdir dir="${dest.lib.dir}"/&gt;<br /> <br />         &lt;javac srcdir="${src.dir}"<br />                 destdir="${dest.classes.dir}"<br />                 debug="${compile.debug}"<br />                 deprecation="${compile.deprecation}"<br />                 optimize="${compile.optimize}"<br />                 source="${compile.source}"<br />                 target="${compile.target}" &gt;<br />         &lt;/javac&gt;<br />     &lt;/target&gt;<br /> <br /> &lt;!-- cleanup --&gt;<br />     &lt;target name="clean" depends="checks"&gt;<br />         &lt;delete dir="${dest.classes.dir}"/&gt;<br />         &lt;delete dir="${dest.lib.dir}"/&gt;<br />         &lt;delete dir="${javadoc.dir}"/&gt;<br />     &lt;/target&gt;<br /> <br /> &lt;!-- packaging --&gt;<br />     &lt;target name="jar" depends="compile"&gt;<br />         &lt;jar destfile="${dest.lib.dir}/${dest.lib.name}" basedir="${dest.classes.dir}"&gt;<br />             &lt;manifest&gt;<br />                 &lt;attribute name="Built-By" value="${user.name}"/&gt;<br />                 &lt;attribute name="Built-On" value="${build.start.time}"/&gt;<br />                 &lt;attribute name="Main-Class" value="${main.class}" /&gt;<br />             &lt;/manifest&gt;<br />         &lt;/jar&gt;<br />     &lt;/target&gt;<br /> <br /> &lt;!-- javadoc --&gt;<br />     &lt;target name="javadoc"&gt;<br />         &lt;mkdir dir="${javadoc.dir}" /&gt;<br /> <br />         &lt;javadoc sourcepath="${src.dir}"<br />                 destdir="${javadoc.dir}"<br />                 author="true"<br />                 version="true"<br />                 private="false"<br />                 packagenames="${javadoc.package.names}"&gt;<br />         &lt;/javadoc&gt;<br />     &lt;/target&gt;<br /> <br /> &lt;!-- check the environment --&gt;<br />     &lt;target name="checks" depends="check.src.dir.set, check.dest.classes.set,<br />                                         check.dest.lib.set, check.javadoc.dir.set,<br />                                          set.src.dir.exists, check.src.dir" /&gt;<br /> <br />     &lt;target name="check.src.dir.set" unless="src.dir" &gt;<br />         &lt;fail message="The property src.dir is not set" /&gt;<br />     &lt;/target&gt;<br /> <br />     &lt;target name="check.dest.classes.set" unless="dest.classes.dir" &gt;<br />         &lt;fail message="The property dest.classes.dir is not set" /&gt;<br />     &lt;/target&gt;<br /> <br />     &lt;target name="check.dest.lib.set" unless="dest.lib.dir" &gt;<br />         &lt;fail message="The property dest.lib.dir is not set" /&gt;<br /> <br />     &lt;target name="check.javadoc.dir.set" unless="javadoc.dir" &gt;<br />         &lt;fail message="The property javadoc.dir is not set" /&gt;<br />     &lt;/target&gt;<br /> <br />     &lt;target name="set.src.dir.exists" &gt;<br />         &lt;available property="src.dir.exists" file="${src.dir}" /&gt;<br />     &lt;/target&gt;<br /> <br />     &lt;target name="check.src.dir" unless="src.dir.exists" &gt;<br />         &lt;fail message="Source directory not found at ${src.dir},<br />                                ${line.separator}make sure the src.dir property is set correctly" /&gt;<br />     &lt;/target&gt;<br /> <br /> &lt;/project&gt;<br /> [/code]<br /> <br /> This build file checks the environment in which it is running to make sure that everything looks correct.  At the top of the file the defaults are set.  Any of these can be overridden if you were to create a file named build.properties in the same directory as the build.xml file.  The idea is that you may need build.properties changed depending on, for example, what O/S you are using at the time.<br /> <br /> Once you have added the package declaration to SimpleHTTPServer.java and moved it to src/com/hotjoe/http/server, just run "ant" in the directory.    You should get an output that looks similar to:<br /> <br /> [code]<br /> [httpserver]$ ant<br /> Buildfile: build.xml<br /> <br /> check.src.dir.set:<br /> <br /> check.dest.classes.set:<br /> <br /> check.dest.lib.set:<br /> <br /> check.javadoc.dir.set:<br /> <br /> set.src.dir.exists:<br /> <br /> check.src.dir:<br /> <br /> checks:<br /> <br /> compile:<br />     [mkdir] Created dir: /home/scott/hotjoe/httpserver/classes<br />     [mkdir] Created dir: /home/scott/hotjoe/httpserver/lib<br />     [javac] Compiling 1 source file to /home/scott/hotjoe/httpserver/classes<br /> <br /> jar:<br />       [jar] Building jar: /home/scott/hotjoe/httpserver/lib/httpserver.jar<br /> <br /> main:<br /> <br /> BUILD SUCCESSFUL<br /> Total time: 3 seconds<br /> [/code]<br /> <br /> Lets start with that and see if there are any issues.]]></description>
				<guid isPermaLink="true">http://forums.hotjoe.com/posts/preList/62/392.page</guid>
				<link>http://forums.hotjoe.com/posts/preList/62/392.page</link>
				<pubDate><![CDATA[Wed, 11 Jan 2006 11:21:23]]> GMT</pubDate>
				<author><![CDATA[ stdunbar]]></author>
			</item>
	</channel>
</rss>
