📄 socketclientfactory.java
字号:
// SocketClientFactory.java// $Id: SocketClientFactory.java,v 1.44 2004/02/10 13:22:40 ylafon Exp $// (c) COPYRIGHT MIT and INRIA, 1996.// Please first read the full copyright statement in file COPYRIGHT.htmlpackage org.w3c.jigsaw.http.socket ;import java.io.IOException;import java.io.PrintStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import org.w3c.jigsaw.http.Client;import org.w3c.jigsaw.http.ClientFactory;import org.w3c.jigsaw.http.httpd;import org.w3c.jigsaw.config.PropertySet;import org.w3c.util.LRUAble;import org.w3c.util.LRUList;import org.w3c.util.ObservableProperties;import org.w3c.util.PropertyMonitoring;import org.w3c.util.Status;import org.w3c.util.SyncLRUList;import org.w3c.util.ThreadCache;class DebugThread extends Thread { SocketClientFactory pool = null; public void run() { while ( true ) { try { sleep(1000*10); // Display some client statistics: SocketClientState cs = null; cs = (SocketClientState) pool.freeList.getHead(); while (cs != null) { System.out.println(cs.client + " reqcount=" + cs.client.getRequestCount() + ", bindcount=" + cs.client.getBindCount()); cs = (SocketClientState)pool.freeList.getNext((LRUAble)cs); } System.out.println("freeCount ="+pool.freeCount); System.out.println("idleCount ="+pool.idleCount); System.out.println("totalCount="+pool.clientCount); System.out.println("estimCount="+pool.clientEstim); System.out.println("Average: "+pool.loadavg); } catch (Exception ex) { ex.printStackTrace(); } } } DebugThread(SocketClientFactory pool) { this.pool = pool; setPriority(Thread.MAX_PRIORITY); }}/** * The client pool is a kind of client factory. * Each time the server gets a new connection, it calls the client pool * to bound a client object (newly created or spared) to handle it. */public class SocketClientFactory implements ClientFactory, PropertyMonitoring, Status { private static final boolean debug = false; private static final boolean debugstats = false; private static final boolean debugthread = false; public static final int MINSPARE_FREE = 5; public static final int MAXSPARE_FREE = 10; public static final int MAXSPARE_IDLE = 20; public static final int MAXTHREADS = 40; public static final int MAXCLIENTS = 32; public static final int IDLETO = 10000; public static final int AVG_LIGHT = 1; public static final int AVG_NORMAL = 2; public static final int AVG_HIGH = 3; public static final int AVG_DEAD = 4; // FIXME doc public final static String MINSPARE_FREE_P = "org.w3c.jigsaw.http.socket.SocketClientFactory.minFree"; // FIXME doc public final static String MAXSPARE_FREE_P = "org.w3c.jigsaw.http.socket.SocketClientFactory.maxFree"; // FIXME doc public final static String MAXSPARE_IDLE_P = "org.w3c.jigsaw.http.socket.SocketClientFactory.maxIdle"; // FIXME doc public final static String MAXTHREADS_P = "org.w3c.jigsaw.http.socket.SocketClientFactory.maxThreads"; // FIXME doc public final static String MAXCLIENTS_P = "org.w3c.jigsaw.http.socket.SocketClientFactory.maxClients"; // FIXME doc public final static String IDLETO_P = "org.w3c.jigsaw.http.socket.SocketClientFactory.idleTimeout"; // FIXME doc public final static String BINDADDR_P = "org.w3c.jigsaw.http.socket.SocketClientFactory.bindAddress"; int minFree = 0; int maxFree = 0; int maxIdle = 0; int maxClients = 0; InetAddress bindAddr = null; int count = 0 ; // number of created clients. httpd server = null ; ObservableProperties props = null ; int busyCount = 0 ; // number of busy clients. LRUList idleList = null; LRUList freeList = null; SocketClientState csList = null; int idleCount = 0 ; int freeCount = 0 ; int clientCount = 0 ; int clientEstim = 0 ; ThreadCache threadcache = null; int loadavg = AVG_LIGHT; boolean alive = true; /** * Give the status of this class as a partial HTML text which will be added * into a block level element * @return a String, the generated HTML */ public String getHTMLStatus() { int idle = 0; int free = 0; int used = 0; int bndc = 0; int reqc = 0; int bnd, req; StringBuffer sb = new StringBuffer(); SocketClientState cs = null; StringBuffer sb1 = null; if (debugstats) { sb1 = new StringBuffer(); } // used clients cs = csList; if (debugstats) { sb1.append("<table border=\"1\" class=\"idle\">\n" + "<caption>Used Clients" +"</caption><tr><th>Id<th>BindCount<th>ReqCount<th>Diff" + "<th>BoundTo</tr>\n"); } while (cs != null) { if (cs.status == SocketClientState.C_BUSY) { InetAddress ia = cs.client.getInetAddress(); bnd = cs.client.getBindCount(); req = cs.client.getRequestCount(); if (debugstats) { sb1.append ("<tr><td>"); sb1.append(cs.id); sb1.append("<td>"); sb1.append(bnd); sb1.append("<td>"); sb1.append(req); sb1.append("<td>"); sb1.append(req - bnd); sb1.append("<td>"); if (ia == null) { sb1.append("Unbound"); } else { sb1.append( cs.client.getInetAddress().getHostAddress()); } sb1.append("</tr>\n"); } used++; bndc += bnd; reqc += req; } cs = cs.csnext; } if (debugstats) { sb1.append("</table>\n"); } // idle clients cs = (SocketClientState) idleList.getHead(); if (debugstats) { sb1.append("<table border=\"1\" class=\"idle\">\n<caption>Idle " +"Clients</caption><tr><th>Id<th>BindCount<th>ReqCount" +"<th>Diff<th>BoundTo</tr>\n"); } while (cs != null) { InetAddress ia = cs.client.getInetAddress(); idle++; bnd = cs.client.getBindCount(); req = cs.client.getRequestCount(); if (debugstats) { sb1.append ("<tr><td>" +cs.id+ "<td>"+ bnd + "<td>" + req + "<td>" + (req - bnd) + "<td>" + ((ia == null) ? "Unbound" : cs.client.getInetAddress().getHostAddress()) + "</tr>\n" ); } bndc += bnd; reqc += req; cs = (SocketClientState)idleList.getNext(cs); } if (debugstats) { sb1.append("</table>\n"); } // free clients cs = (SocketClientState) freeList.getHead(); if (debugstats) { sb1.append("<table border=\"1\" class=\"idle\">\n" + "<caption>Free Clients" + "</caption><tr><th>Id<th>BindCount<th>ReqCount<th>" + "Diff</tr>\n"); } while (cs != null) { free++; bnd = cs.client.getBindCount(); req = cs.client.getRequestCount(); if (debugstats) { sb1.append ("<tr><td>" + cs.id + "<td>"+ bnd + "<td>" + req + "<td>" + (req - bnd) + "\n"); } bndc += bnd; reqc += req; cs = (SocketClientState)freeList.getNext(cs); } if (debugstats) { sb1.append("</table>\n"); } // stats sb.append("<table border class=\"thread\">\n<caption>Thread counts" + "</caption><tr><th>free<th>idle<th>used" + "<th>estim<th>total<th>Load</tr>"); sb.append("<tr><td>"); sb.append(freeCount); sb.append('('); sb.append(free); sb.append(")</td><td>"); sb.append(idleCount); sb.append('('); sb.append(idle); sb.append(")</td><td>"); sb.append(clientCount - freeCount - idleCount); sb.append('('); sb.append(used); sb.append(")</td><td>"); sb.append(clientEstim); sb.append("</td><td>"); sb.append(clientCount); sb.append("</td><td>"); sb.append(loadavg); sb.append("</td></tr></table>\n"); // usage stats sb.append("<table border class=\"usage\">\n<caption>Usage</caption>" + "<tr><th>ReqCount<th>BindCount<th>Diff</tr>\n<tr><td>"); sb.append(reqc); sb.append("</td><td>"); sb.append(bndc); sb.append("</td><td>"); sb.append(reqc -bndc); sb.append("</td></tr></table>\n"); if (debugstats) { sb.append(sb1); } if (debugstats) { cs = csList; sb.append("<table border=\"1\" class=\"idle\">\n<caption>General" + " Status</caption><tr><th>Id<th>Client<th>" + "Status<th>marked<th>Thread</tr>\n"); while (cs != null) { sb.append ("<tr><td>" +cs.id+ "<td>" + ((cs.client == null) ? "None" : "bound") + "<td>" ); switch (cs.status) { case SocketClientState.C_IDLE: sb.append ("Idle"); break; case SocketClientState.C_BUSY: sb.append ("Busy"); break; case SocketClientState.C_FREE: sb.append ("Free"); break; case SocketClientState.C_KILL: sb.append ("Kill"); break; case SocketClientState.C_FIN: sb.append ("Fin"); break; } sb.append ("<td>" + cs.marked); if (cs.client != null) { sb.append("<td>" + cs.client.thread +"</tr>\n"); } else { sb.append("<td>No CLient</tr>\n"); } cs = cs.csnext; } sb.append("</table>\n"); } return sb.toString(); } /** * Some property have changed, update our setting. * @param name The name of the property that has changed. * @return A boolean, <strong>true</strong> if we updated ourself * successfully. */ public boolean propertyChanged (String name) { httpd s = server; if ( name.equals(MINSPARE_FREE_P) ) { minFree = props.getInteger(MINSPARE_FREE_P, minFree); } else if ( name.equals(MAXSPARE_FREE_P) ) { maxFree = props.getInteger(MAXSPARE_FREE_P, maxFree); } else if ( name.equals(MAXSPARE_IDLE_P) ) { maxIdle = props.getInteger(MAXSPARE_IDLE_P, maxIdle); } else if ( name.equals(MAXTHREADS_P) ) { int maxThreads = props.getInteger(MAXTHREADS_P, -1); if ( maxThreads > 0 ) threadcache.setCachesize(maxThreads); } else if ( name.equals(IDLETO_P) ) { int idleto = props.getInteger(IDLETO_P, -1); if ( idleto > 0 ) { threadcache.setIdleTimeout(idleto); } } else if ( name.equals(MAXCLIENTS_P) ) { int newmax = props.getInteger(MAXCLIENTS_P, -1); if ( newmax > maxClients ) { for (int i = maxClients-newmax; --i >= 0; ) addClient(true); } else if ( newmax > 0 ) { maxClients = newmax; } } else if (name.equals(BINDADDR_P)) { try { bindAddr = InetAddress.getByName(props.getString(BINDADDR_P, null)); } catch (Exception ex) { // nothing } } return true ; } /** * Remove this client state from the glohbal client list. * @param cs The client state to remove from the list. */ protected synchronized void deleteClient(SocketClientState cs) { if ( cs.csprev == null ) { csList = cs.csnext; } else if ( cs.csnext == null ) { cs.csprev.csnext = null; } else { cs.csprev.csnext = cs.csnext; cs.csnext.csprev = cs.csprev; } } /** * Factory for creating a new client for this pool. * @param server the target http daemon * @param state the client state holder * @return a new socket client */ protected SocketClient createClient(httpd server, SocketClientState state) { return new SocketClient(server, this, state); } /** * Create a new client for this pool. * @param free A boolean, if <strong>true</strong> the client is inserted * straight into the free list, otherwise, it is not plugged into any * list. * @return A SocketClientState instance, if creation of a new client was * allowed, <strong>null</strong> if no more clients could be created. */ protected synchronized SocketClientState addClient (boolean free) { // Create a new client. csList = new SocketClientState(csList); SocketClientState cs = csList; SocketClient client = createClient(server, cs); cs.client = client; clientCount++; clientEstim++; // Plug into free LRU if required: if ( free ) { cs.status = SocketClientState.C_FREE; freeList.toHead(cs); freeCount++; } return cs ; } /** * We are not using synchronized functions to speed up things, * but it is sometime useful to check that clients are not in a bad * shape */ private final void checkDeadClients() { SocketClientState cs = null; cs = csList; boolean check = true; int idlecount = 0; int freecount = 0; int clientcount = 0; while (cs != null) { if (cs.client != null) { clientcount++; switch(cs.status) { case SocketClientState.C_BUSY: if (cs.client.thread == null) { if (cs.marked) { if ( clientEstim <= maxClients ) { cs.marked = false; ++freeCount; updateLoadAverage(); freeList.toHead(cs); cs.status = SocketClientState.C_FREE; cs.client.done = true; } check = false; } else { cs.marked = true; } } break; case SocketClientState.C_FREE: freecount++; cs.marked = false; break; default: cs.marked = false; break; } } cs = cs.csnext; } // sanity check if (freecount != freeCount) { cs = (SocketClientState) idleList.getHead(); while (cs != null) { idlecount++; cs = (SocketClientState)idleList.getNext(cs); } cs = (SocketClientState) freeList.getHead(); freecount = 0; while (cs != null) { freecount++; cs = (SocketClientState) freeList.getNext(cs); } freeCount = freecount; idleCount = idlecount; } } /** * Update our idea of the current load. * The one important invariant here, is that whenever the free list * becomes empty, then the load average should be equals to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -