å 責äºé
ãã®èšäºã«èšèŒãããŠãããã®ã¯ãã¹ãŠå人çãªå®åçµéšã§ãããã究極ã®çå®ãã®ã¿ã€ãã«ã§ãããšäž»åŒµãããã®ã§ã¯ãããŸããã
åæ
ããã«ã¡ã¯ã ã³ã³ãã¥ãŒã¿ãŒã²ãŒã ãäœãããšã«èå³ããããŸãã ç§ãåžžã«æ°ããããšãæ¹åããåŠãŒããšããŠããç§ã®ãæ°ã«å ¥ãã®æ¹åæ§ã¯ããã©ãŠã¶ããŒã¹ã®ãã«ããã¬ã€ã€ãŒã²ãŒã ã§ãã
Apache Tomcatã¯ã1ã€ã®ã¢ã€ãã¢ã®ãããã¿ã€ããäœæããããã®ãµãŒãã¬ããã³ã³ãããŒãšããŠäœ¿çšãããŸãã 圌ã¯ãhttpãããã³ã«ãä»ããŠã¯ã©ã€ã¢ã³ãéšåãšéä¿¡ããŸãã ãã®ã¿ã€ãã®ã²ãŒã ã§ã¯ãã¹ããŒã ã¯éåžžã«æå¹ã§ãããå®è£ ã¯éåžžã«ç°¡åã§ãã
ããããææå°æ©ãªæé©åã®1ã€ïŒã¯ããããã¯æªãã§ãããããã§ã¯èš±å¯ããããšã«ããŸããïŒã¯ããµãŒããŒãšã¯ã©ã€ã¢ã³ãã®éã«æ°žç¶çãªæ¥ç¶ã䜿çšãããšããã¢ã€ãã¢ã§ããã ãã®ãããªã¹ããŒã ã§ã¯ãåãªã¯ãšã¹ãã§æ¥ç¶ãéãããéãããããæéã¯ç¡é§ã«ãªããŸããã ãã®ã¹ããŒã ãå®è£ ããããã«ãTomcatã®WebSocket APIãæ€èšããŸããããèªè»¢è»ãæžãã®ãé¢çœããªã£ãã®ã§ãç«ã®äžã§ã®éçºã«é¢ãã話ã«åºäŒã£ãŠãã ããã
ããŒã«
ãã®ããããã®ã¢ã€ãã¢ãå®è£ ããããã«ã次ã䜿çšããŸããã
- NetBeans 7.2.1ïŒå®éã«ã¯ããã®åé¡ã解決ããããã«ãã¹ãŠã®Javaã³ãŒããèšè¿°ãããŠããŸã
- Jdk 1.7
- NettyïŒå€æ°ã®æ¥ç¶ã§ãµãŒããŒãã§ããéãçç£çã«ãªãããã«nioã䜿çšããããšã決å®ããããã®ãã¬ãŒã ã¯ãŒã¯ã¯æ£åžžã«æ©èœããŸããã
- ãœã±ããIOïŒã¯ã©ã€ã¢ã³ãåŽ
- Apache Tomcat 7.0.27ïŒãã³ãããŒã¯çš
- MavenïŒããããã¹ãŠãæ§ç¯ãã
建ç¯
ãŸããã¢ããªã±ãŒã·ã§ã³ããžãã¯ãæ€èšããŸãã
ã³ã³ããã¯ãã¡ã€ã³ã¯ã©ã¹SocketServletContainerã§è¡šãããŸãã ã³ã³ãããèµ·å/åæ¢ããã®ã«åœ¹ç«ã¡ããµãŒãã¬ããã管çããã¡ãœãããå«ãŸããŠããŸãã ãã®èšäºã§ã¯ããµãŒãã¬ãããšããçšèªã¯ããµãŒããŒã³ãŒããæã€ã¡ãœãããå«ããªããžã§ã¯ããæããJCPãµãŒãã¬ããä»æ§ãšã¯é¢ä¿ããªãããšã«æ³šæããŠãã ããã ãã®ãããªãªããžã§ã¯ããµãŒãã¬ãããåŒã³åºãæ¹ã䟿å©ã§ãã
å®éã«ã¯ããã¹ãŠã®ãŠãŒã¶ãŒãµãŒãã¬ãããç¶æ¿ãããããŒã¹ã¯ã©ã¹Servletãš ãã»ãã·ã§ã³ã«é¢ããæ å ±ãä¿åãããŠãŒã¶ãŒã«ã¡ãã»ãŒãžãéä¿¡ããããã«äœ¿çšãããæ¥ç¶ã»ãã·ã§ã³ã¯ã©ã¹ïŒ SocketSession ïŒããããŸãïŒãã®çç±ã¯åŸã§èª¬æããŸãïŒã çä¿¡ããã³çºä¿¡ãããã¡ã®ã¯ã©ã¹ïŒ InputBufferããã³OutputBuffer ïŒãããããå®è£ ãããŸããã
ãŸããxml圢åŒã®æ§æãã¡ã€ã«ã解æãããã«ããŒã¯ã©ã¹Configãå®è£ ããå¿ èŠããããŸããã QueueHandlerã¯ã©ã¹ãšTaskHandlerã¯ã©ã¹ã«ã€ããŠèšåããå¿ èŠããããŸã ã
QueueHandlerã¯èŠæ±ãã¥ãŒãã³ãã©ãŒã§ãããåŠçããTaskã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãè¿œå ããã¡ãœãããå«ãŸããŠããŸãã
TaskHandlerã¯Runnableã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ããŸãã runã¡ãœããã«ã¯ãéä¿¡ããããªã¯ãšã¹ãã®åŠçãå«ãŸããŸãã
Taskã¯ã©ã¹ã«ã¯ãå°çãããªã¯ãšã¹ãã«é¢ããæ å ±ïŒãµãŒããŒã«æž¡ããããã©ã¡ãŒã¿ãŒãåç §ãããµãŒãã¬ããïŒããã³ãããã¯ãŒã¯ãæäœããããã®ã¡ãœããïŒèªã¿åã\æžã蟌ã¿ïŒãå«ãŸããŸãã
次ã«ããããã¯ãŒã¯ã䜿çšããäœæ¥ã®ç·šæãæ€èšããŸãã
Nettyã§ã®äœæ¥ã«ã€ããŠã¯è©³ãã説æããŸãããNettyã«é¢ããèšäºã«ã€ããŠã¯Rena4ka habrayuzerã«æè¬ããŸãïŒã å ¬åŒãµã€ãã®habrãŸãã¯ããã¥ã¡ã³ããèªããšããã䟿å©ã«ãªããŸãã Nettyã®ããã°ã©ãã³ã°çµéšã®ãªã人ãåºæ¬ååãç解ããããã«å¿ èŠãªéšåã®ã¿ãæ€èšããŸãã
ServerPipelineFactoryã¯ã©ã¹ã¯ChannelPipelineãã¡ã¯ããªãŒã§ãããNettyãæ©èœããããã«å¿ èŠã§ãã Decoder ã Encoder ã NioHandlerã® 3ã€ã®ã¯ã©ã¹ãå®è£ ããå¿ èŠããããŸãã ã
æåã®2ã€ã¯ããµãŒããŒã«å°çãããã±ããã®ãã³ãã©ãŒã§ãã ãã³ãŒããŒã¯ããããã¯ãŒã¯ããã®ãã±ãããæ£ãã解æãã Taskã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãè¿ããŸãã ãšã³ã³ãŒããŒã¯ã ã¿ã¹ã¯ã€ã³ã¹ã¿ã³ã¹ããããã¯ãŒã¯ã«æ£ããæžã蟌ã¿ãã¯ã©ã€ã¢ã³ãã«éä¿¡ãã責任ããããŸãã
å®éã NioHandlerã¯ãããã¯ãŒã¯ãããŒãžã£ãŒã§ããæ¥ç¶ãåãå ¥ããåŠçã®ããã®ã¿ã¹ã¯ãéä¿¡ããã»ãã·ã§ã³ã管çããŸãã
ãããã³ã«
ã¯ã©ã€ã¢ã³ããšãµãŒããŒéã§éä¿¡ããã«ã¯ãç¬èªã®ãããã³ã«ãå¿ èŠã§ãã ç§ã¯ãããããªãã·ã³ãã«ã§ããã¹ãã«ããããšã決ããŸããã
ãã®çµæãã¯ã©ã€ã¢ã³ãã¯ãservlet_name [sysDiv] request_parametersã®ãããªã¯ãšãªæååããµãŒããŒã«éä¿¡ããŸãã
ã¯ãšãªãã©ã¡ãŒã¿ã®ãªã¹ãã®åœ¢åŒïŒname1 = value1ãname2 = value2ã...
äŸ ïŒãTS [sysDiv]ã¡ãã»ãŒãž= Hello habrahabr.ruãã
ã¯ã©ã€ã¢ã³ãã¯ãå¿çãçæãããµãŒãã¬ãããšæž¡ããããã©ã¡ãŒã¿ãŒã®ãªã¹ãã瀺ãæååãåãåããšããæå³ã§ããããã³ã«ã¯å¯Ÿç§°çã§ããããšã«æ³šæããŠãã ããã
ãããŠãã³ã³ããã®ã³ãŒââãã®æ€èšã«çŽæ¥æž¡ããŸãã ãããããŸãæåã«ã
æ§æãã¡ã€ã«ã®åœ¢åŒ
<?xml version="1.0" encoding="utf-8"?> <config> <address>localhost</address> <port>9999</port> <workThreadCount>2</workThreadCount> <processThreadCount>2</processThreadCount> </config>
workThreadCount-ãããã¯ãŒã¯ããã¡ãã»ãŒãžãåä¿¡ãããããã¯ãŒã¯ã«æžã蟌ãã¹ã¬ããã®æ°ïŒNettyãåæåããããã«å¿ èŠïŒã
processThreadCount-ãµãŒããŒã«å°çãããªã¯ãšã¹ãã®äžè¬çãªãã¥ãŒãåŠçããã¹ã¬ããã®æ°ã å®éã«ã¯ãã¯ãšãªæååã®è§£æããã¹ãŠã®ãµãŒããŒã³ãŒãã®æäœãããã³å¿çã®åœ¢æããããŸãã
SocketServletContainer
ãã®ã¯ã©ã¹ã¯ãäžå¿ãã¯ã©ã¹ã§ãããããã°ã©ã ã®ä»ã®ã¯ã©ã¹ããã¢ã¯ã»ã¹ããæ¹ã䟿å©ãªãããã·ã³ã°ã«ãã³ã§ãã ãããŠããã¡ãããã¢ããªã±ãŒã·ã§ã³ããšã«ãµãŒããŒã®ã³ããŒã1ã€å«ãŸããŠããããšãæå³ããŸãïŒãããã£ãŠãã¹ã¬ããã»ãŒããªã·ã³ã°ã«ãã³å®è£ ã¯å¿ èŠãããŸããïŒã ç§ã®æèŠã§ã¯ãããã¯è«ççã§ãã
public class SocketServletContainer { private Channel channel; private ServerBootstrap networkServer; private QueueHandler queueHander; private Map<String, Servlet> servlets; private Config conf; private static SocketServletContainer server= null; private static List<SocketSession> list= new ArrayList<SocketSession>(); public List<SocketSession> getListSession() { return list; } static public SocketServletContainer getInstance() { if (server==null) { server= new SocketServletContainer(); } return server; } private SocketServletContainer() { conf= new Config("conf.xml"); // , - Exception. try { conf.read(); } catch(Exception e) { throw new ContainerInitializeException(e.toString()); } servlets= new HashMap<String, Servlet>(); } public void start() { // Netty ExecutorService bossExec = new OrderedMemoryAwareThreadPoolExecutor(1, 400000000, 2000000000, 60, TimeUnit.SECONDS); ExecutorService ioExec = new OrderedMemoryAwareThreadPoolExecutor(conf.getWorkThreadCount(), 400000000, 2000000000, 60, TimeUnit.SECONDS); networkServer = new ServerBootstrap(new NioServerSocketChannelFactory(bossExec, ioExec, conf.getWorkThreadCount())); networkServer.setOption("backlog", 500); networkServer.setOption("connectTimeoutMillis", 10000); networkServer.setPipelineFactory(new ServerPipelineFactory()); channel = networkServer.bind(new InetSocketAddress(conf.getAddress(), conf.getPort())); // queueHander= new QueueHandler(conf.getProcessThreadCount()); System.out.println("Ready"); } // «» public void stop() { if (channel.isOpen()) { ChannelFuture future= channel.close(); future.awaitUninterruptibly(); } queueHander.stop(); } public QueueHandler getQueueHandler() { return this.queueHander; } // public void registerServlet(Servlet servlet, String name) { // - HashMap. synchronized(servlets) { if (!servlets.containsKey(name)) { servlets.put(name, servlet); } } } public Servlet getServlet(String name) { return servlets.get(name); } }
ãµãŒãã¬ãã
ããã§ã¯ãã¹ãŠãã·ã³ãã«ã§æ確ã§ãã doRequestã¡ãœããã¯ããã®ãµãŒãã¬ããã®åŒã³åºããæ瀺ãããã±ãããå°çãããšåŒã³åºãããŸãã
Zam ïŒdoRequestã¡ãœããã«ã»ãã·ã§ã³ãæž¡ãããšã¯ããµãŒãã¬ãããå©çšå¯èœãªãã¹ãŠã®ã»ãã·ã§ã³ã®ãªã¹ããååŸããŠã¡ãã»ãŒãžãéä¿¡ã§ããããã«ããããã«è¡ãããŸãã ããšãã°ããã£ãããå®è£ ããå Žåã
abstract public class Servlet { abstract public void doRequest(InputBuffer input, OutputBuffer output, SocketSession session); }
SocketSession
åã»ãã·ã§ã³ã«ã¯åºæã®IDããããŸãã æ¥ç¶ããã20,000ã®ã¯ã©ã€ã¢ã³ãã®IDããã¯ããŒã ã®ããŒã«ããããŸãã ãã®å¶éãè¶ ãããšããµãŒããŒã¯ã»ãã·ã§ã³ãäœæããããšãããšãã«ãšã©ãŒãèšé²ããéã¯ã©ã€ã¢ã³ããšã©ãŒã¡ãã»ãŒãžãéä¿¡ããŠãã£ãã«ãéããŸãã
ããŒã«ãµã€ãºã®å€ã¯çµéšçã«èšç®ããæ¹ãé©åã§ããçæ³çã«ã¯ããµãŒããŒäžã§åæã«æ¥ç¶å¯èœãªã¯ã©ã€ã¢ã³ãã®æ倧æ°ããããããã«å€§ããããå¿ èŠããããŸãã
public class SocketSession { private static byte[] idPool; public int generateId() { synchronized(idPool) { if (idPool==null) { idPool= new byte[20000]; for (int j=0;j<idPool.length;j++) { idPool[j]=0; } } for (int j=0;j<idPool.length;j++) { if (idPool[j]==0) { idPool[j]=1; return j; } } return -1; } } private int id; private Channel channel; // List . public SocketSession(Channel channel) { this.channel= channel; this.id= generateId(); // if (this.id==-1) { OutputBuffer out= new OutputBuffer(); out.setPar("error", "Connection limit error"); send(out, "System Servlet"); // System.err.println("Connection limit error"); return; } SocketServletContainer.getInstance().getListSession().add(this); } public int getId() { return id; } // . . public void send(OutputBuffer output, String servletName) { synchronized(channel) { channel.write(new Task(servletName, output.toString())); } } // , , - «» public void close() { synchronized(idPool) { idPool[this.id]= 0; } channel.close(); SocketServletContainer.getInstance().getListSession().remove(this); } }
å ¥åãããã¡
åæåã¯ã³ã³ã¹ãã©ã¯ã¿ãŒã§è¡ããããœãŒã¹æååã«ã¯ãæå®ããã圢åŒã®ã¯ãšãªãã©ã¡ãŒã¿ãŒã®ãªã¹ããå«ãŸããŠããå¿ èŠããããŸãã
public class InputBuffer { private Map<String, String> map= new HashMap<String, String>(); public InputBuffer(String source) { String[] par= source.split(","); for (int j=0; j< par.length; j++) { if (!par[j].contains("=")) { continue; } String[] data= par[j].split("="); if (data.length<2) { System.err.println("Parsing Error"); continue; } map.put(data[0], data[1]); } } public String getPar(String key) { return map.get(key); } }
OutputBuffer
ã¯ã©ã¹ã€ã³ã¿ãŒãã§ã€ã¹ã¯éåžžã«ç°¡åã§ãã éèŠãªæ³šæç¹ã¯ãtoStringïŒïŒã¡ãœããããªãŒããŒã©ã€ãããå¿ èŠãããããšã§ããããã¯ã SocketSessionã¯ã©ã¹ã§å¿çã圢æããããã«äœ¿çšãããããã§ãã
public class OutputBuffer { private List<String> list= new ArrayList<String>(); public void setPar(String key, String par) { list.add(key+"="+par); } @Override public String toString() { StringBuilder res= new StringBuilder(); for (int j=0; j< list.size();j++) { res.append(list.get(j)); if (j!=list.size()-1) { res.append(","); } } return res.toString(); } }
æ§æ
SocketServletContainerã§äœ¿çšãããŠãããã®ããã€ã³ã¿ãŒãã§ã€ã¹ãæ確ã§ãããã€ã³ã¿ãŒãããäžã®Javaã«ã¯xmlããŒãµãŒã®å®è£ ãå€æ°ããããããã®ã¯ã©ã¹ã®å®è£ ã¯æäŸããŸããã
å人çã«ã¯ãDOMããŒãµãŒã䜿çšããŸããã
ãã¥ãŒãã³ãã©ãŒ
ãã®ã¯ã©ã¹ã¯å®è£ ãéåžžã«ç°¡åã§ãã å éšã«ã¯ãã¿ã¹ã¯ãåŠçããã¹ã¬ããããŒã«ïŒ TaskHandler ïŒãå«ãŸããŠããŸãã ç§ã¯ãèšç»ãä¿¡é Œã§ããå®èšŒæžã¿ã®threadPoolå®è£ ã«ç§»è¡ããŸããã Executors.newFixedThreadPoolïŒnïŒãã¡ã¯ããªãŒã䜿çšããŠããŒã«ãäœæããŸãã
stopã¡ãœãããåŒã³åºããããšããã¥ãŒå ã®æ¢åã®ã¿ã¹ã¯ã¯åŠçãããŸãããæ°ããTaskHandlersã¯åŠçãããŸããã
public class QueueHandler { private ExecutorService threadPool; private int threadPoolSize; public QueueHandler(int size) { threadPoolSize= size; threadPool= Executors.newFixedThreadPool(threadPoolSize); } public void stop() { threadPool.shutdown(); } public void addTaskToProcess(Task task, SocketSession session) { threadPool.execute(new TaskHandler(task, session)); } }
ã¿ã¹ã¯ãã³ãã©ãŒ
ããã§ããã¹ãŠãéåžžã«ç°¡åã§ãã ãã¬ãŒã€ãŒã®ã»ãã·ã§ã³ãšåŠçãããã¿ã¹ã¯ã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒã«è»¢éãããŸãã
public class TaskHandler implements Runnable{ private Task task; private SocketSession session; public TaskHandler(Task task, SocketSession session) { this.task= task; this.session= session; } @Override public void run() { // Servlet servlet= SocketServletContainer.getInstance().getServlet(task.getServletName()); OutputBuffer output= new OutputBuffer(); // , . if (servlet==null) { output.setPar("error", "servlet not found"); session.send(output, "Error Message"); return; } // servlet.doRequest(new InputBuffer(task.getBuffer()),output, session); // . session.send(output, task.getServletName()); } }
ã¿ã¹ã¯
Taskãªããžã§ã¯ãã«ã¯ããservlet nameããã£ãŒã«ããšãbufferããã£ãŒã«ãããããŸãã ãããã¡ã¯ã¯ãšãªãã©ã¡ãŒã¿ã®æååã§ãã
Nettyãæ©èœããã«ã¯ãã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãååŸãããããã€ãã«æžã蟌ãã ãããããã«ãéçãªæžã蟌ã¿/èªã¿åãã¡ãœãããå¿ èŠã§ãã
public class Task { private String servletName=""; private String buffer=""; public Task(String servletName, String buffer) { this.servletName= servletName; this.buffer= buffer; } public Task() { } public String getServletName() { return servletName; } public String getBuffer() { return buffer; } // public void get(ChannelBuffer buffer) { int length= buffer.readInt(); byte[] bytes= new byte[length]; buffer.readBytes(bytes); String input= new String(bytes); String[] data= input.split(java.util.regex.Pattern.quote("[sysDiv]")); if (data.length<2) { System.err.println("Parsing error"); return; } this.servletName= data[0]; this.buffer= data[1]; } // public void send(ChannelBuffer buffer) { String output= this.servletName + "[sysDiv]"+ this.buffer; buffer.writeInt(output.getBytes().length); buffer.writeBytes(output.getBytes()); } public static Task read(ChannelBuffer buffer) { Task task= new Task(); task.get(buffer); return task; } public static void write(Task task, ChannelBuffer buffer) { task.send(buffer); } }
ãããã¯ãŒã¯éš
çŽæã©ãããç§ã¯nettyã詳现ã«æäœããããšãæ€èšããŸãããã³ãŒããæäŸããããžãã¯ã®å®è£ ã«é¢é£ãããã€ã³ãã説æããã ãã§ãã
ServerPipelineFactory
public class ServerPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new Encoder(),new Decoder(),new NioHandler()); } }
ãã³ãŒããŒ
ãã±ããã¯ã次ã®åœ¢åŒã§ãµãŒããŒã«å°çããŸããæåã®4ãã€ãã¯ãæçšãªãããŒã¿ã®é·ãã次ã«ããŒã¿èªäœã§ãã ãã³ãŒããŒã¯èªã¿åããå®è£ ããŠãããããäžã®ã¬ã€ã€ãŒã§ã¯ãããŒã¿ããŸã å®å šã«å°çããŠããªããšããäºå®ãèããããšã¯ã§ããŸããã
public class Decoder extends ReplayingDecoder<DecoderState> { public enum DecoderState { READ_LENGTH, READ_CONTENT; } public Decoder() { super(DecoderState.READ_LENGTH); } private int length; @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } @Override protected Object decode(ChannelHandlerContext arg0, Channel arg1, ChannelBuffer buffer, DecoderState state) { switch (state) { case READ_LENGTH: length = buffer.readInt(); checkpoint(DecoderState.READ_CONTENT); case READ_CONTENT: ChannelBuffer frame= buffer.readBytes(length); // task Task task= Task.read(frame); checkpoint(DecoderState.READ_LENGTH); return task; default: throw new Error( "Shouldn't reach here" ); } } }
ãšã³ã³ãŒããŒ
public class Encoder extends OneToOneEncoder { @Override protected Object encode(ChannelHandlerContext channelhandlercontext, Channel channel, Object obj) throws Exception { // Task, if(!(obj instanceof Task)) { return obj; } Task task= (Task)obj; ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(); // task Task.write(task, buffer); return buffer; } }
ããªãã³ãã©ãŒ
ãã®ãªããžã§ã¯ãã¯ããããã¯ãŒã¯ã®æäœãã¯ã©ã€ã¢ã³ãã®æ¥ç¶ãã¡ãã»ãŒãžã®åä¿¡ãåæãªã©ã®äž»ãªã€ãã³ããåŠçããŸãã
public class NioHandler extends SimpleChannelUpstreamHandler { private SocketSession session; @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // session= new SocketSession(e.getChannel()); System.out.println("Has connect"); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { session.close(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { if(e.getChannel().isOpen()) { // Task QueueHandler. Task message= (Task)e.getMessage(); SocketServletContainer.getInstance().getQueueHandler().addTaskToProcess(message, session); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { // . , . session.close(); e.getCause().printStackTrace(System.err); ctx.getChannel().close(); } }
ãµãŒãã¬ããã®äŸ
public class TS extends Servlet { @Override public void doRequest(InputBuffer input, OutputBuffer output, SocketSession session) { output.setPar("request", input.getPar("message")+session.getId()); } }
ä»çµã¿ãŸãã¯ã¢ããªã±ãŒã·ã§ã³ã®ã¡ã€ã³ã¯ã©ã¹
å®éãã¢ããªã±ãŒã·ã§ã³ã«ã¯ããã»ã©å€ãã®ã³ãŒãè¡ããªãããã¹ãŠãã·ã³ãã«ã§ééçã§ãã
public class App { public static void main( String[] args ) throws ContainerInitializeException { SocketServletContainer server= SocketServletContainer.getInstance(); server.registerServlet(new TS(), "TS"); server.start(); } }
ããã€ãã®ãã¹ã
ããŠãã³ã³ããã¯æžãããŠãããåäœããŸãã ç§ã¯ããã®ããã®ã¯ã©ã€ã¢ã³ãã©ãããŒãäœæããããšãæ°ã«ããŸããã§ãããç§ã¯ãœã±ããã«çŽæ¥æžã蟌ãããšã«èªåèªèº«ãå¶éããŸãããããã¯æ¬¡ã®ããã«èŠããŸãïŒ
socket = new Socket("127.0.0.1", 9999); DataOutputStream dos= new DataOutputStream(socket.getOutputStream()); DataInputStream dis= new DataInputStream(socket.getInputStream()); String buffer= "TS[sysDiv]message=IloveJava"; dos.writeInt(buffer.getBytes().length+4); dos.writeInt(buffer.getBytes().length); dos.write(buffer.getBytes()); dos.flush();
äžè¬ã«ãèšäºã®åé ã§è¿°ã¹ãããã«ããã®ãããªã·ã¹ãã ã®äœæã¯ãç§ãèªåèªèº«ã«èš±å¯ããããšã«ããææå°æ©ãªæé©åã®1ã€ã§ãã ãããã£ãŠãç§ãã¡å šå¡ãæžããã®ã§ãããã€ãã®ãã¹ããè¡ããªãã®ã¯æããªããšã§ãã
å®éããã®ãœãªã¥ãŒã·ã§ã³ãhttpã§å®è¡ãããŠãããµãŒãã¬ããã³ã³ãããšæ¯èŒããããšã«ããŸããã
ãã¹ãã®ããã«ãTomcatã§ã¹ãã³ãããµãŒãã¬ãããšãäœæãããã³ã³ãããŒå ã§åäœãããµãŒãã¬ãããéçºãããŸããã
ZamïŒ Tomcatãæ£åžžã«ãµããŒãããWebãœã±ããã¯ããã®ã²ãŒã ãããžã§ã¯ãã®å®è£ ã§ã¯èæ ®ãããŠããªãã£ããããhttpãããã³ã«ã®ããã©ãŒãã³ã¹ãšãœã±ããã®ãœãªã¥ãŒã·ã§ã³ãæå³çã«æ¯èŒããŸããã
ãã¹ãã®ç¹åŸŽïŒ
- äž¡æ¹ã®ãµãŒãã¬ããã¯ãã»ãŒåãæäœãå®è¡ããŸãããã€ãŸããåãè¡ãåºåã¹ããªãŒã ã«æžã蟌ã¿ãŸããã
- èå³ã®ãããã¹ããã©ã¡ãŒã¿ãŒã¯ãèŠæ±ãåŠçãããšãã®ãµãŒããŒããã®å¿çæéã§ã
- 枬å®ã¯ããŒã«ã«ãã¹ãã§è¡ãããŸãã
- æšæºã®JavaèšèªããŒã«ã䜿çšããŠå¿çæéãåŸãŸãã
- ç¹å®ã®æ°å€ã«ã¯èå³ããããŸããã§ãããããã¹ãã¯éåžžã«ã倧ãŸãã«ãæžãããŠãããããçµæã®é åºãæ¯èŒããããšã«èå³ããããŸããã
- åãã¹ãã§ãåããã©ã¡ãŒã¿ãŒã䜿çšããŠ10,000件ã®ã¯ãšãªãå®è¡ãããã®åŸå¹³åå€ãèšç®ããŸãã
çµæã¯æ¬¡ã®ãšããã§ããå¹³åããŠãTomcatã®1ã€ã®ã空ã®ããµãŒãã¬ããã®åŠçã«ã¯0ã99ããªç§ããããŸããã
ãã®èšäºã§èª¬æãããŠããã³ã³ããã¯ã 0.09ããªç§ã§åæ§ã®ã¿ã¹ã¯ã«å¯ŸåŠããŸããã
æ¡éãã®2ã€ã®çµæããããŸãã ãããããœã±ããã䜿çšãããšããã¢ã€ãã¢ã¯ãé床ã®ããã§ã¯ãªãããµãŒããŒããã¯ã©ã€ã¢ã³ãã«æãå·®ã䌞ã¹ãããšãã§ããå¿ èŠããããããç§ã«æãã€ãããšããäºå®ãèæ ®ãããšãçµæã¯æºè¶³ã®ãããã®ãšèããããšãã§ããŸãã
TODOïŒ
åæ§ã®ã·ã¹ãã ã«å®è£ ã§ããçããªã¹ãããããŸããã
- å ¥åããŒã¿ã®æ€èšŒã å ¥åãããã¡ãŒã«æ€èšŒïŒæååãã¹ã¯ïŒã¡ãœãããè¿œå ãããšã察å¿ãããã©ã¡ãŒã¿ãŒã®ããŒã¿åãã¹ã¯ã䜿çšããŠãæååã ãã§ãªãç®çã®åã«èªåçã«å€æãããŸãã 次ã®ããã«ãªããŸãïŒvalidateïŒ "messageïŒStringãcountïŒint"ïŒ;
- ããŒã¿æå·åãè¿œå ããŸãã ãããã³ã«ã¯ããã¹ãã§ããããã€ã[]ãããã¡ãŒãæžã蟌ãŸããã®ã¯writeUTF8ïŒïŒã§ã¯ãªãããã®ããã§ãã ã€ã³ã¿ãŒãã§ãŒã¹Crypto {}ãå®è£ ã§ããŸããããã«ã¯ãcodeïŒïŒããã³encodeïŒïŒã®2ã€ã®ã¡ãœããããããŸãã ãŸããæå·åã¢ã«ãŽãªãºã ãç°¡åã«å€æŽãŸãã¯éžæã§ããããã«ããã®ãããªã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ã¯SocketServletContainerïŒïŒã«æž¡ãå¿ èŠããããŸãã
- ïŒTomcatã§è¡ãããŠããããã«ïŒã¢ãããŒã·ã§ã³ãåŠçãããµãŒãã¬ããã®åæåãé ãããŸãã
- ããªãã¿ã·ãŒã«ãã䜿çšããå ¥åãããã¡ã®ããå®å šãªè§£æ
- ãã®ãããªã·ã¹ãã ã§å¿ èŠã«ãªããããããªãä»ã®äŸ¿å©ãªå°ããªãã®ã®æã
çµè«ã®ä»£ããã«
ã³ã³ããã®çµæã¯ç§ã®æåŸ ãå®å šã«æºãããŸããã NIOã䜿çšããããšã§ããããŒãçµæžçã«æ¶è²»ããæ¢åã®ããŒããŠã§ã¢çšã®ã³ã³ãããæ§æããŠãå¯èœãªéãå¹ççã«åäœããããšãã§ããŸããã
ã³ã³ãããæäŸããæ©èœã«ããããã±ãã解æãªã©ã®ãäœã¬ãã«ããªããšãå¿é ããã«ã¢ããªã±ãŒã·ã§ã³ãç°¡åã«éçºã§ããŸãïŒTomcatã§ã®éçºã«äœ¿çšãããŠããããã«æããããã®ãã¹ãŠ:)ïŒã
ããããå®éã«ã¯ããã®ãããªãœãªã¥ãŒã·ã§ã³ãå®éã®ãããžã§ã¯ãã®åºç€ãšããŠäœ¿çšããããšãæ¢ããŠããŸããã§ããããªããªããç§ã«ãšã£ãŠã¯ããã¡ãããœã±ããã®ååšã¯éåžžã«æçšã ããã§ãïŒãµãŒããŒãšã¯ã©ã€ã¢ã³ãã®ãã£ãŒãããã¯ã«ãšã£ãŠïŒããååãšããŠãããã¯éèŠã§ã¯ãããŸãã ããããé·å¹Žã«ããã£ãŠå®èšŒãããTomcatã®ããã©ãŒãã³ã¹ãšä¿¡é Œæ§ããããŠäœå人ãã®éçºè ãçåãæããããããšã¯ãããŸããã
ç§ã¯ãå®è£ ãããã·ã¹ãã ããçããããhttpãããã³ã«ã䜿çšããã®ããããªããéèŠã§ã¯ãªãå Žæã§äœ¿çšããäºå®ã§ããããšãã°ããã£ããã®å®è£ ã«æé©ã§ãã
ãã®èšäºãèªè ã«ãšã£ãŠèå³æ·±ããã®ã§ããã誰ãã«ãšã£ãŠåœ¹ç«ã€ããšãé¡ã£ãŠããŸãã ç§ã¯å šäœåãäŒããããšããŸãããããã¶ããæšè«ãšã³ãŒãã®éãå€ãããŸããã ææžã«é¢ãã質åãææ¡ãèããŠããããæããŸãã