/** * GossipServer.java * Copyright (c) 1998 Yoon Kyung Koo. All rights reserved. * * VERSION HISTORY * Version 1.0 1999/03/16 * First release * Version 1.0b 1999/03/17 * bug fixed around locales and ... * specified locale as EUC_KR * * @version 1.0b 1999/03/17 * @author Yoon Kyung Koo */ import java.io.*; import java.net.*; import java.util.*; class GossipServer { static int DEFAULT_PORT = 8888; static String BUFFER_FILE="buffer.txt"; final static int MAX_USER=20; final static int MAX_BUFFER=20; ServerSocket server = null; Vector clients = new Vector(); Vector buffer = new Vector(MAX_BUFFER); // create empty Vector // static initializer static { Locale.setDefault(Locale.KOREA); TimeZone.setDefault(new SimpleTimeZone(9*60*60*1000,"KST")); } // inner class class Client extends Thread { Socket socket = null; BufferedReader in = null; PrintWriter out = null; // constructor Client (Socket socket) throws IOException { this.socket = socket; this.in = new BufferedReader( new InputStreamReader(socket.getInputStream(), "EUC_KR")); this.out = new PrintWriter( new OutputStreamWriter(socket.getOutputStream(), "EUC_KR"), true /* auto flush */); setName("guest"); // use Thread class's name start(); // run this client thread } public void run() { try { while (true) { // note that readLine() is a blocking operation String line = in.readLine(); if (line == null) { // null means End Of Stream close(); break; } System.out.println(getName()+':'+line); GossipServer.this.processLine(this, line); } } catch (IOException ie) { System.out.println(getName()+":IOException. "+ie.getMessage()); close(); } } public void close() { synchronized (GossipServer.this) { try { if (in!=null) in.close(); } catch (Exception e) {} if (out!=null) out.close(); try { if (socket!=null) socket.close(); } catch (Exception e) {} socket=null; } GossipServer.this.sendAllNames(); //send an updated names list } } // constructor public GossipServer(int port) { // first, create server socket try { server = new ServerSocket(port); } catch (IOException ie) { System.out.println("Cannot create server socket"); System.exit(1); } System.out.println("Gossip server ready on "+port+"..."); initializeBuffer(); while (true) { try { Socket socket = server.accept(); if (clients.size()>MAX_USER) { Client tmp = new Client(socket); tmp.out.println("(¼­¹ö)ÇöÀç Á¢¼ÓµÈ »ç¿ëÀÚ°¡ ³Ê¹« ¸¹½À´Ï´Ù."); tmp.close(); continue; } broadcast("(¼­¹ö)»õ·Î¿î »ç¿ëÀÚ°¡ ´ëÈ­¹æ¿¡ µé¾î¿À¼Ì½À´Ï´Ù.", false); // add new client to client list Client client = new Client(socket); synchronized (this) { clients.addElement(client); } client.out.println("(¼­¹ö)Á¢¼ÓµÇ¾ú½À´Ï´Ù."); sendInitMessage(client); } catch (IOException ie) { System.out.println("IOException :"+ie.getMessage()); } } } public static void main(String args[]) { int port = DEFAULT_PORT; if (args.length>=2) { // Usage: java GossipServer port_no buffer_file_name BUFFER_FILE=args[1]; try { port = Integer.parseInt(args[0]); } catch (NumberFormatException nfe) { } } new GossipServer(port); } private void processLine(Client client, String line) { if (line.length() > 256) return ; // too long if (line.startsWith("##name##")){ //instruction to change name if (line.length()<9) return; client.setName(line.substring(8)); //name is the rest of line client.out.println("(¼­¹ö)À̸§ÀÌ "+line.substring(8) +"À¸·Î ¹Ù²î¾ú½À´Ï´Ù."); if (client.out.checkError()) { // check error System.out.println("Error while sending message."); client.close(); } sendAllNames(); //send an updated names list return; //don't echo this string } else if (line.startsWith("##help##")){ //instruction to get help client.out.println("(µµ¿ò¸»)##help## ¹Ù·Î ÀÌ ³»¿ëÀ» º¸¿©ÁÝ´Ï´Ù."); client.out.println(" ##name##°³¶ËÀÌ Á¢¼ÓÀÚÀÇ À̸§À» °³¶ËÀÌ·Î ÁöÁ¤ÇÕ´Ï´Ù."); client.out.println(" ##quit## Á¾·áÇÕ´Ï´Ù."); client.out.println(" ##only##À̸§:³»¿ë 'À̸§'¿¡°Ô ±Í¿§¸»·Î ³»¿ëÀ» º¸³À´Ï´Ù."); client.out.println(" ±×³É ±ÛÀ» ¾´ ´ÙÀ½ ¿£Å͸¦ Ä¡¸é Á¢¼ÓÇÑ ¸ðµç ÀÌ¿¡°Ô ±ÛÀ» º¸³À´Ï´Ù."); if (client.out.checkError()) { // check error System.out.println("Error while sending message."); client.close(); } return; } else if (line.startsWith("##only##")){ // instruction to send private message int j; int pos=line.indexOf(':'); if ( pos <8 ) return; if (!sendPrivate(line.substring(8, pos), "("+client.getName()+"ÀÇ ±Í¿§¸»)"+line.substring(pos+1))) { client.out.println("(¼­¹ö)±Í¿§¸» º¸³»±â ¿¡·¯ÀÔ´Ï´Ù."); if (client.out.checkError()) { // check error System.out.println("Error while sending message."); client.close(); } return; } client.out.println("("+line.substring(8,pos)+"¿¡°Ô ±Í¿§¸»)"+line.substring(pos+1)); if (client.out.checkError()) { // check error System.out.println("Error while sending message."); client.close(); } return ; //don't echo this string } else if (line.equals("##quit##")){ String name=client.getName(); client.close(); broadcast("(¼­¹ö)"+name+"´ÔÀÌ Á¢¼ÓÀ» Á¾·áÇÏ¿´½À´Ï´Ù.", false); //tell everyone return; } else // broadcast to all broadcast(client.getName()+':'+line, true); } private void broadcast(String message, boolean append) { synchronized (this) { for (Enumeration enum=clients.elements(); enum.hasMoreElements(); ) { Client client = (Client) enum.nextElement(); if (client == null) continue; if (client.socket == null) { // if closed socket clients.removeElement(client); continue; } client.out.println(message); if (client.out.checkError()) { // check error System.out.println("Error while sending message."); client.close(); } } } if (append) appendBuffer("("+getTimeStamp()+')'+message, true); } private synchronized boolean sendPrivate(String receiver, String message) { boolean result=false; for (Enumeration enum=clients.elements(); enum.hasMoreElements(); ) { Client client = (Client) enum.nextElement(); if (client == null) continue; if (client.socket == null) { // if closed socket clients.removeElement(client); continue; } if (receiver.equals(client.getName())) { client.out.println(message); if (client.out.checkError()) { // check error System.out.println("Error while sending message."); client.close(); } // name can be multiple in this implementation result = true; } } return result; } private void sendInitMessage (Client client) { if (!buffer.isEmpty()) for (Enumeration enum = buffer.elements() ; enum.hasMoreElements() ;) { client.out.println((String)enum.nextElement()); if (client.out.checkError()) { // check error System.out.println("Error while sending message."); client.close(); break; } } } private void sendAllNames() { //sends the name list to every body String names = new String("##names##"); //start with indicator synchronized(this) { for (Enumeration enum=clients.elements(); enum.hasMoreElements(); ) { Client client = (Client) enum.nextElement(); if (client == null) continue; if (client.socket == null) { // if closed socket clients.removeElement(client); continue; } names+=client.getName()+'|'; } } broadcast(names, false); //echo the names to everyone } void initializeBuffer() { // ¹öÆÛ ÆÄÀÏÀÇ ³»¿ëÀ» ÀÐ¾î ¹öÆÛ¸¦ ÃʱâÈ­ÇÑ´Ù. File file=new File(BUFFER_FILE); if (!file.exists() || !file.canRead()) return; synchronized (buffer) { BufferedReader in = null; try { // cannot user FileReader // because FileReader cannot specify char encoding in = new BufferedReader( new InputStreamReader(new FileInputStream(file), "EUC_KR"), 1024); // buffer size } catch (FileNotFoundException fnfe) { return; } catch (Exception e) { System.out.println("initialize buffer error : "+e.getMessage()); return; } // reading operation try { String string=null; while ((string=in.readLine()) != null) { appendBuffer(string+'\n', false); } } catch (IOException ie) { System.out.println("File read error : "+ie.getMessage()); } finally { try { in.close(); } catch (IOException ie2) {} } } //end of synchronized } void appendBuffer(String text, boolean isWriting){ // ¹öÆÛ¿¡ ´ëÈ­ ³»¿ëÀ» ¿Ã¸°´Ù. synchronized (buffer) { if (buffer.size()>=MAX_BUFFER) buffer.removeElementAt(0); buffer.addElement(text); } if (isWriting) { synchronized (buffer) { PrintWriter out = null; // initialize try { // cannot user FileWriter // because FileWriter cannot specify char encoding out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( new FileOutputStream(BUFFER_FILE, true /* append */), "EUC_KR"))); } catch (IOException ie) { System.out.println("append to buffer error : "+ie.toString()); return; } // writing operation out.print(text+'\n'); // print() method never throws IOException, // so we should check error while printing if (out.checkError()) System.out.println("append to buffer error : write error."); out.close(); } // end of synchronized } // end of if (isWriting) } String getTimeStamp() { Date date= new Date(); java.text.SimpleDateFormat fmt= new java.text.SimpleDateFormat(); fmt=(java.text.SimpleDateFormat) java.text.DateFormat.getDateTimeInstance( java.text.DateFormat.SHORT, java.text.DateFormat.SHORT, java.util.Locale.KOREAN); return fmt.format(date); } // end of getTimeStamp() }