Данный пример был взят из книги "UNIX
сервер", написанной Сергеем Дунаевым, а тот в
свою очередь этот пример взял с сайта www.javasoft.com Пример очень простого многопоточного НТТР-сервера:
import java.io.*; import java.net.*; import java.util.*; class WebServer implements HttpConstants { protected static void p(String s) { System.out.println(s); } protected static Properties props = new Properties(); static Vector threads = new Vector(); static File root; static int port = 80; static int timeout = 0; static int workers = 10; public static ServerSocket ss; static void loadProps() throws IOException { File f = new File(System.getProperty("user.dir")+File.separator+ "WebServer.ini"); if(f.exists()) { InputStream is=new BufferedInputStream(new FileInputStream(f)); props.load(is); is.close(); String r = props.getProperty("root"); if(r != null) { root = new File(r); if(!root.exists()) { throw new Error(root + " doesn't exist as server root"); } } r = props.getProperty("port"); if(r != null) { port = Integer.parseInt(r); } r = props.getProperty("timeout"); if(r != null) { timeout = Integer.parseInt(r); } r = props.getProperty("workers"); if(r != null) { workers = Integer.parseInt(r); } } } static void printProps() { p("root="+root); p("port="+port); p("timeout="+timeout); p("workers="+workers); } public static void main(String[] a) throws Exception { loadProps(); printProps(); for(int i=0;i<workers;i++) { Worker w=new Worker(); (new Thread(w, "worker #"+i)).start(); threads.addElement(w); } ss = new ServerSocket(port); while (true) { Socket s = ss.accept(); Worker w=null; synchronized (threads) { if(threads.isEmpty()) { Worker ws = new Worker(); ws.setSocket(s); (new Thread(ws, "additional worker")).start(); } else { w = (Worker) threads.elementAt(0); threads.removeElementAt(0); w.setSocket(s); } } } } } class Worker extends WebServer implements HttpConstants, Runnable { final static int BUF_SIZE=2048; static final byte[] EOL={(byte)'\r', (byte)'\n' }; /* buffer to use for requests */ byte[] buf; /* Socket to client we're handling */ private Socket s; Worker() { buf=new byte[BUF_SIZE]; s=null; } synchronized void setSocket(Socket s) { this.s=s; notify(); } public synchronized void run() { while(true) { if (s== null) { /* nothing to do */ try{ wait(); } catch (InterruptedException e) { /* should not happen */ continue; } } try { handleClient(); } catch (Exception e) { e.printStackTrace(); } /* go back in wait queue if there's fewer * than numHandler connections. */ s=null; Vector pool = WebServer.threads; synchronized (pool) { if (pool.size()>= WebServer.workers) { /* too many threads, exit this one */ return; } else { pool.addElement(this); } } } } void handleClient() throws IOException { InputStream is = new BufferedInputStream(s.getInputStream()); PrintStream ps = new PrintStream(s.getOutputStream()); /* we will only block in read for this many milliseconds * before we fail with java.io.lnterruptedlOException, * alt which point we will abandon the connection. */ s.setSoTimeout(WebServer.timeout); s.setTcpNoDelay(true); /* zero out the buffer from last time */ for(int i = 0; i <BUF_SIZE; i++) { buf[i]= 0; } try{ int nread = 0, r = 0; outerloop: while (nread < BUF_SIZE) { r=is.read(buf, nread, BUF_SIZE nread); if (r== -1) { /* EOF */ return; } int i=nread; nread +=r; for (; i < nread; i++) { if (buf[i]== (byte)'\n' || buf[i]== (byte)'\r') { /* read one line */ break outerloop; } } } /* are we doing a GET or just a HEAD */ boolean doingGet; /* beginning of file name */ int index; if (buf[0]== (byte)'G' && buf[1]== (byte)'E' && buf[2]== (byte)'T' && buf[3]== (byte)' ') { doingGet=true; index=4 } else if (buf[0]== (byte)'H' && buf[1]== (byte)'E' && buf[2]== (byte)'A' && buf[3]== (byte)'D' && buf[4]== (byte)' ') { doingGet=false; index=5; } else { /* we don't support this method */ ps.print("HTTP/1.0 " + HTTP_BAD_METHOD + " unsupported method type:"); ps.write(buf, 0, 5); ps.write(EOL); ps.flush(); s.close(); return; } int i = 0; /* find the file name, from: * GET /foo/bar.html HTTP/1.0 * extract "/foo/bar.html" */ for (i = index; i < nread; i++) { if (buf[i]== (byte)' ') { break; } } String fname = (new String(buf, 0, index, i-index)).replace('/', File.separatorChar); if (fname.startsWith(File.separator)) { fname = fname.substring(1); } File targ= new File(WebServer.root, fname); if (targ.isDirectory()) { File ind = new File(targ, "index.html"); if (ind.exists()) { targ = ind; } } boolean OK=printHeaders(targ, ps); if (doingGet) { if (OK) { sendFile(targ, ps); } else { send404(targ, ps); } } } finally { s.close(); } } boolean printHeaders(File targ, PrintStream ps) throws IOException { boolean ret = false; int rCode=0; if (!targ.exists()) { rCode = HTTP_NOT_FOUND; ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " not found"); ps.write(EOL); ret = false; } else { rCode = HTTP_OK; ps.print("HTTP/1.0 " + HTTP_OK + " OK"); ps.write(EOL); ret = true; } ps.print("Server: Simple Java"); ps.write(EOL); ps.print("Date: " + (new Date())); ps.write(EOL); if (ret) { if (!targ.isDirectory()) { ps.print("Content-length: "+targ.length()); ps.write(EOL); ps.print("Last Modified: " + (new Date(targ.lastModified()))); ps.write(EOL); String name = targ.getName(); int ind = name.lastIndexOf('.'); String ct = null; if (ind > 0) { ct = (String) map.get(name.substring(ind)); } if (ct == null) { ct = "unknown/unknown"; } ps.print("Content-type: " + ct); ps.write(EOL); } else { ps.print("Content-type: text/html"); ps.write(EOL); } } return ret; } void send404(File targ, PrintStream ps) throws IOException { ps.write(EOL); ps.write(EOL); ps.println("Not Found\n\n"+ "The requested resource was not found.\n"); } void sendFile(File targ, PrintStream ps) throws IOException { InputStream is = null; ps.write(EOL); if (targ.isDirectory()) { return; } else { is = new FileInputStream(targ.getAbsolutePath()); } try{ int n; while ((n = is.read(buf)) > 0) { ps.write(buf, 0, n); } } finally { is.close(); } } /* mapping of file extensions to content-types */ static java.util.Hashtable map = new java.util.Hashtable(); static { fillMap(); } static void setSuffix(String k, String v) { map.put(k, v); } static void fillMap() { setSuffix("", "content/unknown"); setSuffix(".uu", "application/octet-stream"); setSuffix(".exe", "application/octet-stream"); setSuffix(".ps", "application/postscript"); setSuffix(".zip", "application/zip"); setSuffix(".sh", "application/x-shar"); setSuffix(".tar", "application/x-tar"); setSuffix(".snd", "audio/basic"); setSuffix(".au", "audio/basic"); setSuffix(".wav", "audio/x-wav"); setSuffix(".gif", "image/gif"); setSuffix(".jpg", "image/jpeg"); setSuffix(".jpeg", "image/jpeg"); setSuffix(".htm", "text/html"); setSuffix(".html", "text/html"); setSuffix(".text", "text/plain"); setSuffix(".c", "text/plain"); setSuffix(".cc", "text/plain"); setSuffix(".c++", "text/plain"); setSuffix(".h", "text/plain"); setSuffix(".pi", "text/plain"); setSuffix(".txt", "text/plain"); setSuffix(".Java", "text/plain"); } } interface HttpConstants { /** 2XX: generally "OK" */ public static final int HTTP_OK = 200; public static final int HTTP_CREATED = 201; public static final int HTTP_ACCEPTED = 202; public static final int HTTP_NOT_AUTHORITATIVE = 203; public static final int HTTP_NO_CONTENT = 204; public static final int HTTP_RESET = 205; public static final int HTTP_PARTIAL = 206; /** 3XX: relocation/redirect */ public static final int HTTP_MULT_CHOICE = 300; public static final int HTTP_MOVED_PERM = 301; public static final int HTTP_MOVED_TEMP = 302; public static final int HTTP_SEE_OTHER = 303; public static final int HTTP_NOT_MODIFIED = 304; public static final int HTTP_USE_PROXY = 305; /** 4ХХ: client error */ public static final int HTTP_BAD_REQUEST = 400; public static final int HTTP_UNAUTHORIZED = 401; public static final int HTTP_PAYMENT_REQUIRED = 402; public static final int HTTP_FORBIDDEN = 403; public static final int HTTP_NOT_FOUND = 404; public static final int HTTP_BAD_METHOD = 405; public static final int HTTP_NOT_ACCEPTABLE = 406; public static final int HTTP_PROXY_AUTH = 407; public static final int HTTP_CLIENT_TIMEOUT = 408; public static final int HTTP_CONFLICT = 409; public static final int HTTP_GONE = 410; public static final int HTTP_LENGTH_REQUIRED = 411; public static final int HTTP_PRECON_FAILED = 412; public static final int HTTP_ENTITY_TOO_LARGE = 413; public static final int HTTP_REQ_TOO_LONG = 414; public static final int HTTP_UNSUPPORTED_TYPE = 415; /**5XX: server error*/ public static final int HTTP_SERVER_ERROR = 500; public static final int HTTP_INTERNAL_ERROR = 501; public static final int HTTP_BAD_GATEWAY = 502; public static final int HTTP_UNAVAILABLE = 503; public static final int HTTP_GATEWAY_TIMEOUT = 504; public static final int HTTP_VERSION = 505; } Работоспособный исходный код можно взять здесь, а так же к серверу
прилагается INI-файлик следующего
содержания:
root=\Wwwroot port=80 workers=15 timeout=0 root - локальный каталог, из которого Web-сервер
берёт файлы; Для того чтобы этот сервер заработал,
необходимо откомпилировать его Продолжение следует .... |
|
|
|