?? httpcookiedistributionalgorithm.java.temp
字號:
/* ***************************************************************************** * $Id$ ***************************************************************************** * A distribution algorithm which ensures clients speak to a * consistent server. Similar in effect to a hash selection algorithm * but implemented by feeding the client an HTTP cookie which records * the target that the client is connected to. Obviously only works for * HTTP servers, but provides a better distribution than a standard hash * algorithm because many clients behind a web proxy or NAT router don't * all get stuck on the same server. ***************************************************************************** * Copyright 2003 Jason Heiss * * This file is part of Distributor. * * Distributor is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Distributor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Distributor; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***************************************************************************** */package oss.distributor;import java.util.HashMap;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;class HTTPCookieDistributionAlgorithm extends DistributionAlgorithm implements Runnable{ Map clientHeaderBuffers; int hashTimeout; Map ipMap; Map lastConnectTime; static final int DEFAULT_HEADER_BUFFER_SIZE = 4096; int maxHeaderSize; Thread thread; /* * Because the distribution algorithms are instantiated via * Class.forName(), they must have public constructors. */ public HTTPCookieDistributionAlgorithm( Distributor distributor, Element configElement) { super(distributor); /* * hashTimeout defines how long we keep a record of the last * target a given client was sent too. Set it too long and * you'll use a lot of memory on a busy server. But it needs to * be long enough that client sessions get sent to the right * server. The right value is highly dependant on your * environment. Reasonable values probably range anywhere from * one hour to a couple of days. */ hashTimeout = 1800000; try { hashTimeout = Integer.parseInt(configElement.getAttribute("hash_timeout")); } catch (NumberFormatException e) { logger.warning("Invalid hash timeout, using default: " + e.getMessage()); } logger.config("Hash timeout: " + hashTimeout); // *** // Need to read this from configElement maxHeaderSize = 32768; clientHeaderBuffers = new HashMap(); ipMap = new HashMap(); lastConnectTime = new HashMap(); thread = new Thread(this, getClass().getName()); } /* * This allows Distributor to delay some of our initialization until * it is ready. There are some things we need that Distributor may * not have ready at the point at which it constructs us, so we wait * and retrieve them at the start of run(). */ public void startThread() { thread.start(); } // On a new connection we need to look for a cookie in the HTTP // headers. If there is one we prefer that target, just like the // hash algorithm (i.e. prefer that target and fail back to round // robin if the preferred target is down). If there isn't a cookie, // or if the preferred target is unavailable and we connect the // client to a new target, we set a cookie in the return traffic. // http://wp.netscape.com/newsref/std/cookie_spec.html // // Possible cookie fields and defaults: // expires User's session // domain Server hostname // path Document path // secure No // // We need a cookie as follows // Set-Cookie: DistributorTarget=<target> path=/ // The HTTP RFC (2616) says headers are US-ASCII, so we need to // specify that as the charset for Java to use when decoding strings // from the input stream. public void tryToConnect(SocketChannel client) { clientHeaderBuffers.put( client, ByteBuffer.allocate(DEFAULT_HEADER_BUFFER_SIZE)); // *** // Register with selector } public void run() { List failed; Iterator iter; SocketChannel client; // Finish any initialization that was delayed until Distributor // was ready. finishInitialization(); while(true) { // *** select { foreach sockchan { while (readMore) { ByteBuffer buf = clientHeaderBuffers.get(sockchan); // Bump the buffer's limit by one, thus allowing // read() to read one byte buf.limit(buf.position() + 1); r = sockchan.read(buf); if (r == 1) { // Ignore leading CRLF's per // section 4.1 of RFC 2616 // *** if (buf.position() == 1) { } // // Look for end of headers // // Grab the last 4 bytes of the buffer byte[] lastBit = new byte[4]; // Back the buffer position up by 3 so we // get 4 bytes buf.position(buf.position() - 3); buf.get(lastBit); // Restore the buffer position buf.position(buf.position() + 3); // The end of the headers will be signified // by CRLFCRLF, i.e. a start/header line // followed by a blank line. if (lastBit[0] == '\r' && lastBit[1] == '\n' && lastBit[2] == '\r' && lastBit[3] == '\n') { } } else if (r == 0) { // No more data can be read for now, but // we still haven't seen the end of the // headers. Ratchet the buffer's limit // back by one so it's ready for the next // time around. buf.limit(buf.position()); } else if (r == -1) { // EOF encountered but end of headers not // found. This connection is bogus, discard // it. } } } } // Give any failed connections back to TargetSelector failed = checkForFailedConnections(); iter = failed.iterator(); while(iter.hasNext()) { client = (SocketChannel) iter.next(); targetSelector.addUnconnectedClient(client); } // Purge old entries from ipMap synchronized(lastConnectTime) { iter = lastConnectTime.entrySet().iterator(); while(iter.hasNext()) { Entry timeEntry = (Entry) iter.next(); addr = (InetAddress) timeEntry.getKey(); lastConnect = ((Long) timeEntry.getValue()).longValue(); if (lastConnect + hashTimeout < System.currentTimeMillis()) { synchronized(ipMap) { ipMap.remove(addr); } lastConnectTime.remove(addr); } } } // *** logger.fine("connections.size(): " + connections.size()); logger.fine("connectStartTime.size(): " + connectStartTime.size()); logger.fine("ipMap.size(): " + ipMap.size()); logger.fine("lastConnectTime.size(): " + lastConnectTime.size()); } } public void connectionNotify(Connection conn) { // Store a mapping for this client's IP address so that we can // inject the appropriate cookie later synchronized(ipMap) { logger.finer( "Storing mapping from " + conn.getClient().socket().getInetAddress() + " to " + conn.getTarget()); ipMap.put( conn.getClient().socket().getInetAddress(), conn.getTarget()); } // And record the time to allow us to dump old entries from the // maps after a while (see the run method). synchronized(lastConnectTime) { lastConnectTime.put( conn.getClient().socket().getInetAddress(), new Long(System.currentTimeMillis())); } } // If we have any data queued up from the cookie search, prepend it public ByteBuffer reviewClientToServerData( SocketChannel client, SocketChannel server, ByteBuffer buffer) { // *** } // Inject a Set-Cookie header if appropriate public ByteBuffer reviewServerToClientData( SocketChannel server, SocketChannel client, ByteBuffer buffer) { // *** }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -