예전부터 StringTokenizer 와 String.split()의 차이가 궁금했었습니다. 그냥 보기에는 둘 다 똑같은 기능처럼 보이거든요.

  특히나 .split()은 알아서 배열까지 만들어 주기에 굉장히 편리해서, 학교에서 배울 때 말고는 직접 일하면서 StringTokenizer를 써본 적이 없었습니다.

  StringTokenizer 와 String.split() (내용을 보시려면 클릭)

  그랬는데 이 글을 보니 몇 가지 차이점이 있군요. 개인적으로 주목한 건, .split()은 구분자 사이에 문자열이 없어도 공백인 배열을 만들지만 StringTokenizer는 무시한다는 점이군요.

  일전에 만들었던 프로그램 중에 .split()을 썼더니 구분자가 연속으로 들어오면 그걸 다 빈 공백값으로 만드는 바람에 일일이 번거롭게 걸러내게 프로그래밍했었는데 StringTokenizer를 쓰면 간단하게 해결될 일이었습니다..._no

  역시 Java는 API를 얼마나 잘 알고 있느냐에 따라 괜한 삽질을 안 하게 되는 것 같습니다.(물론 그 많은 API를 다 알기에는 한계가 있긴 하지만요.)
Java Map(HashMap, TreeMap, Hashtable)

1. Collection
  • Map은 key와 value를 가진 집합이며, 중복을 허용하지 않는다.
  • 즉, 한개의 key에 한개의 value가 매칭된다.
  • java.util 패키지에 여러 집합들을 사용하기 위한 여러 interface와 class 들이 정의되어 있다.
2. HashMap
  • HashMap은 Map interface를 implements 한 클래스로서 중복을 허용하지 않는다.
  • Map의 특징인 key와 value의 쌍으로 이루어지며, key 또는 value 값으로써 null을 허용한다.
  • 아래의 예는 HashMap을 사용한 간단한 예제이다.

    import java.util.*;


    public class HashMapTest
    {
        public static void main(String argv[])
        {
            HashMap hm = new HashMap();
            System.out.println(hm.put("aaa", "111"));
            System.out.println(hm.put("bbb", "222"));
            System.out.println(hm.put("aaa", "444"));
            System.out.println(hm.put("ccc", "333"));   
            System.out.println(hm.put("ccc", null));      
           
            System.out.println("HashMap size : " + hm.size());
           
            Set set = hm.keySet();
            Object []hmKeys = set.toArray();
            for(int i = 0; i < hmKeys.length; i++)
            {
                String key = (String)hmKeys[i];  
                System.out.print(key);
                System.out.print(" - ");
                System.out.println((String)hm.get(key));
            }
        }
    }


    /**
    실행:java HashMapTest
    결과:
    null
    null
    111
    null
    333
    HashMap size : 3
    ccc - null
    bbb - 222
    aaa - 444
    */

3. TreeMap
  • TreeMap역시 중복을 허용하지 않으며, key와 value의 쌍으로 이루어져 있다.
  • HashMap과 다른 점은 SortedMap을 implements 하였으므로, key 값들에 대한 정렬이 이루어진다는 점이다.
  • 아래의 예는 TreeMap을 사용하여 각 요소가 몇몇 이나 나왔는지 알아보는 간단한 예제이다.

    import java.util.*;

    public class Freq

    {
        private static final Integer ONE = new Integer(1);

        public static void main(String args[])

        {
            Map m = new TreeMap();

            // Initialize frequency table from command line
            for (int i=0; i < args.length; i++)

            {
                Integer freq = (Integer) m.get(args[i]);
                m.put(args[i], (freq==null ? ONE :
                                new Integer(freq.intValue() + 1)));
            }

            System.out.println(m.size()+" distinct words detected:");
            System.out.println(m);
        }
    }


    /**
    실행:java Freq if it is to be it is up to me to delegate
    결과:
    8 distinct words detected:
    {be=1, delegate=1, if=1, is=2, it=2, me=1, to=3, up=1}
    */

4. Hashtable
  • Hashtable Map interface를 implements 한 클래스로서 중복을 허용하지 않는다.
  • Map의 특징인 key와 value의 쌍으로 이루어지며, key 또는 value 값으로써 null을 허용하지 않는다.(HashMap과의 차이점)
  • 아래의 예는 HashTable을 사용한 간단한 예제이다.

    import java.util.*;

    public class HashtableTest

    {

        public static void main(String argv[])
        {
            Hashtable ht = new Hashtable();
            System.out.println(ht.put("aaa", "111"));
            System.out.println(ht.put("bbb", "222"));
            System.out.println(ht.put("aaa", "444"));
            System.out.println(ht.put("ccc", "333"));   
           
            System.out.println("Hashtable size : " + ht.size());
           
            System.out.println("aaa value : " + (String)ht.get("aaa");
           
        }
    }


    /**
    실행:java HashMapTest
    결과:
    null
    null
    111
    null
    Hashtable size : 3
    aaa value : 444
    */



 

간단한사용 예제

<%@page import="java.util.*" contentType="text/html;charset=euc-kr"%>
<%

     HashMap hm = new HashMap();

     List al = new ArrayList();


     hm.put("name","진우");
     hm.put("nick","쪼");

     al.add( hm );


     hm = new HashMap();
     hm.put("name","애희");
     hm.put("nick","줴인");
     al.add( hm );


     // for문 내에 사용되는 변수들

     HashMap getHm = new HashMap();

     String sName = null;

     String sNick = null;

     for ( int i=0; i<al.size(); i++ ){
          getHm = (HashMap)al.get(i);
          sName = (String)getHm.get("name");
          sNick = (String)getHm.get("nick");
          out.println( (i+1)+"번째 이름 : "+sName+", 애칭 : "+sNick+"<br>" );
     }

     // 어려운거 없다
%>


출력:

1번째 이름 : 진우, 애칭 : 쪼
2번째 이름 : 애희, 애칭 : 줴인
*개발 하실때 참고 하세요..

package LogManager;

import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class LogTrace {
 
 private String _filename;
 private Logger _logger;
 private FileHandler _fHandler;
 
 public LogTrace(String filename){
  this._filename  = filename;
  this._logger = java.util.logging.Logger.getLogger("net.anfamily.logging");
 }
 
 public LogTrace(String filename, java.util.logging.Logger logger){
  this._filename  = filename;
  this._logger = logger;
 }
 
 /**
  * 로그를 저장한다.
  */
 public void writeLog(String log){
  try{
   this._fHandler = new java.util.logging.FileHandler(this._filename,true);
   
   _logger.addHandler(this._fHandler);
   _logger.setLevel(java.util.logging.Level.ALL);
   SimpleFormatter formatter = new SimpleFormatter();
   
   //로그 메시지를 남긴다.
   _logger.log(Level.FINER,log);
   _logger.log(Level.FINE,log);
   _logger.log(Level.FINER,log);
   _logger.log(Level.CONFIG,log);
   _logger.log(Level.INFO,log);
   _logger.log(Level.WARNING,log);
   _logger.log(Level.SEVERE,log);
  }catch(Exception e){
   e.printStackTrace();
   System.out.println("");
  }
 }
 
 
 /**
  *로그를 저장한다.
  * @param log
  * @param filename
  */
 public void writeLog(String log, String filename){
  try{
   this._fHandler = new java.util.logging.FileHandler(this._filename,true);
   
   _logger.addHandler(this._fHandler);
   _logger.setLevel(java.util.logging.Level.ALL);
   SimpleFormatter formatter = new SimpleFormatter();
   this._fHandler.setFormatter(formatter);
   
   _logger.log(Level.FINER,log);
   _logger.log(Level.FINER,log);
   _logger.log(Level.FINE,log);
   _logger.log(Level.CONFIG,log);
   _logger.log(Level.INFO,log);
   _logger.log(Level.WARNING,log);
   _logger.log(Level.SEVERE,log);
   
  }catch(Exception e){
   e.printStackTrace();
  }
 }
 
 /**
  * 로그를 저장한다.
  * @param log
  * @param logger
  * @param handler
  */
 public static void writeLog(String log,Logger logger, ConsoleHandler handler){
 
  try{
   logger.addHandler(handler);
   logger.setLevel(java.util.logging.Level.ALL);
   SimpleFormatter formatter = new SimpleFormatter();
   handler.setFormatter(formatter);
   
   logger.log(Level.FINEST,log);
   logger.log(Level.FINER,log);
   logger.log(Level.FINE,log);
   logger.log(Level.CONFIG,log);
   logger.log(Level.INFO,log);
   logger.log(Level.WARNING,log);
   logger.log(Level.SEVERE,log);
  }catch(Exception e){
   e.printStackTrace();
   System.out.println("");
  }
 }
 
 /**
  * 로그를 파일로 저장한다.
  * @param filename
  * @param log
  * @param logger
  */
 public static void writeLog(String log,Logger logger,String filename){
  try{
   FileHandler handler = new java.util.logging.FileHandler(filename,true);
   logger.addHandler(handler);
   logger.setLevel(java.util.logging.Level.ALL);
   SimpleFormatter formatter = new SimpleFormatter();
   handler.setFormatter(formatter);
   
   logger.log(Level.FINEST,log);
   logger.log(Level.FINER,log);
   logger.log(Level.FINE,log);
   logger.log(Level.CONFIG,log);
   logger.log(Level.INFO,log);
   logger.log(Level.SEVERE,log);
  }catch(Exception e){
   e.printStackTrace();
   System.out.println("");
  }
 
 
 }
 
}
==========================================================================================

package LogManager;

import java.util.logging.ConsoleHandler;
import java.util.logging.Logger;

public class LogingTest {

 public LogingTest(){
 }
 
 public static void main(String [] args){
  LogTrace logs = new LogTrace("c:\\log_Test100917.txt");
  logs.writeLog("Test입니다.");
 
  LogTrace.writeLog("Test입니다._1", Logger.getLogger("new.anfamily.net"), new ConsoleHandler());
  LogTrace.writeLog("Test입니다._2", Logger.getLogger("new.anfamily.net"), "c:\\log_Test100917_1.txt");
 }
}
=======================================================================================

실행 결과

2010. 9. 17 오전 11:15:31 LogManager.LogTrace writeLog
아주 자세히: Test입니다._2
2010. 9. 17 오전 11:15:31 LogManager.LogTrace writeLog
더 자세히: Test입니다._2
2010. 9. 17 오전 11:15:31 LogManager.LogTrace writeLog
자세히: Test입니다._2
2010. 9. 17 오전 11:15:31 LogManager.LogTrace writeLog
구성: Test입니다._2
2010. 9. 17 오전 11:15:31 LogManager.LogTrace writeLog
정보: Test입니다._2
2010. 9. 17 오전 11:15:31 LogManager.LogTrace writeLog
심각: Test입니다._2

 
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지

'Java' 카테고리의 다른 글

Java Map(HashMap, TreeMap, Hashtable)  (0) 2010.09.17
로그 남기기.. -java  (0) 2010.09.17
TCP/IP Socket 프로그램 구현시 고려사항공부/Java  (0) 2010.08.19
httpsession 을 이용한 로그인 관리  (0) 2010.08.13
Web Server 와 WAS  (0) 2010.07.28
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=1009171849


제목 : TCP/IP Socket 프로그램 구현시 고려사항
글쓴이: 이원영(javaservice)   2001/12/24 14:30:49  조회수:6479  줄수:96
 
TCP/IP Socket 프로그램 구현시 고려사항

CPU나 메모리와 같은 자원은 항상 한계점이 있기 마련입니다. 그 한계점에 도달했을 때,
어떻게 동작케 하도록 조정하겠느냐의 문제가 매우 중요합니다. 이러한 고민의 여부가
때론 프로그래머의 수준이 실무적인 경험이 있느냐 그렇지 않느냐의 차이로 나타납니다.

TCP/IP Socket 프로그램을 짤때, 크게 수준에 따라 네가지 방법이 있습니다.

첫째, ServerSocket에서 accept()상태에서 대기하다가 accept()에서 요청이 떨어지면
그제서야 new YourThread(client) 를 생성하여 해당 Socket 요청을 처리하는 Thread를
만들고, ServerSocket은 다시 accept()의 while loop로 돌아가는 것이지요.
이것의 문제는 두가지인데, 하나는 매 요청마다 Thread가 생성되고 처리가 끝나면
GC에 의해 사라지므로 부하를 매우 많이 받는 구조라는 것입니다. 두번째 문제는, 이렇게
짰다는 것은 한계상황에 대한 처리구조가 없다는 것입니다. 몇개의 Thread가 Job을
동시에 처리하면 해당 H/W의 한계점에 이르를 것인지를 확인하고, 그 개수제한을 두어야
하는데, 전혀 이러한 고려가 없으니, 일정한 부하 이상의 상황에 직면하게 되면 요청이
지속적으로 큐잉된다거나 혹은 생각지 못했던 Exception들을 만나게 될 수도 있습니다.
어떤 자원이 고갈되어 한계상황에 직면했을 땐, 추가적인 요청들에 대해서는 fail을
발생하여 곧바로 return케 하여야만이 장애가 일어 나지 않습니다.
PS: 이를 Peek Point Contron 기법이라고 명명하였었습니다
PPC(Peek Point Control) 기법
http://www.javaservice.net/~java/bbs/read.cgi?m=qna&b=consult&c=r_p&n=996642473

두번째 방법은 Thread Pooling을 사용하는 방식입니다. 대부분의 웹어플리케이션서버의
엔진소스에서 서블렛/JSP를 처리하는 내부적인 방식이 이렇게 되어 있습니다.
요청을 처리하는 Thread는 해당 프로그램이 처음 뜰 때 이미 50개면 50개, 100개면
100개가 모두 기동됩니다. 그 Thread들은 run()메소드에서 while loop를 돌며 무한루프에
빠져 있는데, run() 메소드 첫부분에서 모든 Thread들이 어떤 lock 객체에 synchronized
되어 wait()상태에 빠져 있습니다.
만약, ServerSocket의 accept()에서 요청이 들어오면, 기본적인 정보만 추출하여 이를
적당한 queue에 해당 client socket을 큐잉하고, Thread들이 wait()되어 있는 lock을
notify()/notifyAll() 시킵니다. 그러면 수 많은 Thread들 중 한 Thread가 깨어나
queue의 값을 꺼내어 SocketClient 요청을 처리하고 자신은 다시 무한루프에 의해
다시 wait() 됩니다.
이 같은 구조는 앞서의 문제를 모두 해결합니다. 즉, 매번 Thread를 생성하지 않으니
부하가 없고, 또, 초기에 몇개의 Thread들을 기동시켜두느냐는 결국 동시에 수행할
개수제한의 효과가 되는 것이지요. 그 개수는 Performance Tuning의 방법론에 따라
해당 H/W와 S/W환경에 맞게 적정값으로 조정되는 것이지요.

세번째 방법은 Socket Server측에서 Thread Pooling을 사용하는 것은 두번째 방법과
동일한데, Socket Client와 Server 사이의 TCP/IP Socket연결자체를 어떻게 Pooling
할 것인가의 문제가 추가됩니다. 지금까진 매번 Socket을 open하고 close하는 구조로
가져갔을 겁니다. 그러나, socket open은 부하가 걸리는 작업이므로 미리 socket을
열어두고 이를 pool에 넣어 둔 후, 필요시 pool에서 꺼내와 사용하는 것이 보다 효율적일
것입니다. 이는 Socket client와 server 측 모두에서 고려되어야 합니다. 5개면 5개,
10개면 10개 미리 Socket들이 맺어져 있고, 필요시 가져다 사용하고 모두 사용하고 난
뒤 곧바로 close하는 것이 아니라 pool로 돌려보내는 방법이지요.
이 방법은 socket을 매번 open/close하지 않으니 성능향상을 볼 수 있습니다. 그러나
단점은 Pool에 연결되어 있는 Socket들이 어떤 N/W 장애로 인해 물리적인 단절이 됐을
경우, 이를 어떻게 Recovery 할 것인가의 이슈가 추가로 고려되어야 합니다.

네번째 방법은 앞서 세번째가지의 기법이 모두 적용된 상태에서 다시 추가 됩니다.
즉, 앞서의 방법은 socket pool을 사용하므로, send를 날린 후 아직 receive를 받지 않는
동안 이 TCP/IP socket은 멍청하게 놀리고 있는 결과가 되고 맙니다. 즉, 실질적인
데이타는 이용되고 있지 않으면서도 매우 많은 수의 TCP/IP Socket이 필요하게 됩니다.
그래서 send 전용 socket과 receive전용 Socket을 별도로 구분하게 됩니다. 결국, send용
queue와 receive용 queue가 만들어져야 하고, client는 send용 queue에 넘길 데이타를
채운 후, send용 Thread들을 notify시킵니다. 곧바로 recevice queue에서 자신의 데이타가
오기를 기다려야 겠지요. Recieve용 Socket에 달려 있는 receive 용 Thread는 데이타가
오는 즉시 receive용 queue에 값을 채워넣고, 자신의 데이타가 오기를 기다리는 Thread
의 lock을 notify 시킵니다. (잘 깨워야겠지요, 모두 깨울것이냐, 혹은 해당 데이타에
관련된 것만 깨울 것인가가 고민되겠지요)
이 경우는 또한, send후 receive하기까지의 Timeout옵션을 지정할 수 있는 잇점도 가질
수 있습니다.
단, 이 경우의 단점은 성능은 가장 빠르지만, 서로 다른 데이타들이 영향을 미칠 수
있습니다. 앞서 보낸 데이타에 이용된 send socket이 장애를 일으키면 뒤따라 보낸 데이타
역시 깨어질 수 있는 것이지요.
또, 자칫 구현을 잘못하면, 동일한 Socket으로만 계속 데이타를 보내려는 시도를 하게
됩니다. OutputStream의 write() 는 순식간에 끝나지만, 실질적인 데이타는 OS나 네트웍
카드의 Send Queue에 대기중에 있을 수 있으며 아직 상대방에 받지 않았을 수 있습니다.
이 때, 같은 Socket에다 또 다시 데이타를 날리면 계속 큐잉만 일어나고, send용과
receive용을 구분했던 장점들을 제대로 살리지 못하게 되는 것이지요.


주고 받는 데이타는 반드시 header와 body로 구분된 약정된 프로토콜을 정의해서
사용해야 합니다. 예를 들면 10byte을 먼저 받아서 기본적인 정보와 body에 따라올
실제 데이타의 길이을 확인하여 해당 길이만큼의 body 데이타를 다시 읽는 것과 같은
동작이지요. 만약, header가 부정확한 정보들로 채워져 있거나 header에서 명시된 것보다
body데이타가 짧다면 적절한 에러처리를 해야 겠지요. OutputStream으로 단 한번에
write()를 한 byte[] 데이타들이, 받는 측에서 InputStream의 read(buf)를 통해 곧바로
받을 것이라고 여기는 경향이 있습니다.
N/W의 상황에 따라 몇 byte씩 나눠서 날아가지요. 에러가 나기전까지, timeout이 되기
전까지, 그리고 모든 데이타가 올 때 까지 loop를 돌면서 끝까지 받아내야 한다는 것을
아셔야 합니다. 아래글을 참고하세요.

Java Socket Client  read 시 data 한계
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=976117970


PS: 시간이 나면 참한 샘플들을 제공하겠지만, .....

================================================
  자바서비스넷 이원영
  E-mail: javaservice@hanmail.net
  PCS:011-898-7904
================================================


제목 : Re: TCP/IP Socket 프로그램 구현시 고려사항
글쓴이: 최용하(smashing)   2001/12/28 14:59:04  조회수:3121  줄수:23
 
안녕하세요. 이원영 과장님의 글 읽어보니 참 좋은 글이네요.
이 글을 애초에 볼 수 있었다면 그 수많은 시행착오를 거치지 않을 수 있었을텐데 ^^

밑에 첨부한 소스는 실제 모은행에서 인터넷뱅킹과 eCRM 시스템에서 사용되는 TCP/IP
Socket 통신 프로그램입니다.
제가 직접 구현하였으며 그동안 수많은 시행착오를 거치면서 정제되었습니다.
스레드풀링 방식으로 세번째에 해당하는 모델이고요 미약하나마 N/W 장애나
프로세스 상태로 인해 커넥션이 단절되었을 경우에 대한 Recovery 기능도 있습니다.

Peek Point Control 은 다음 네가지 부분에서 적절히 처리됩니다.
1. Established 되어있는 Socket Connection 을 항상 일정갯수 유지 (30개)
2. notify 를 받으려고 wait 하고 있는 스레드 갯수를 한정 (20개)
3. wait 하고 있는 스레드 시간 제약 (20초)
4. 호스트와의 타임아웃은 30초

- 소스역할
Connection.java - 호스트와 통신부분(send & receive 및 에러처리시 자원반환부분 중요)
BankObject.java - 생성된 소켓객체
BankQueue.java - 커넥션풀링을 할수 있게 소켓객체들을 담아놓은 큐

도움이 되었음 좋겠네요
참 고맙지.
HttpSession 객체를 이용한 세션관리
 
Login.html
 
<html>
<body>
<form action="session.jsp" method="post">
ID <input type="text" name="id"><br>
Pass <input type="password" name="passwd"><p>
<input type="submit" value="전송">
</form>
</body>
</html>
 
 
session.jsp
 
<%@ page contentType="text/html;charset=euc-kr" session="false"%>
<%         request.setCharacterEncoding("euc-kr"); %>
<%
             HttpSession session = request.getSession(true);
             //세션을 생성
             String name = request.getParameter("name");
             String id = request.getParameter("id");
             String passwd = request.getParameter("passwd");
            
             //세션저장 (플래그, 값)
             session.setAttribute("login.name", name);
             session.setAttribute("login.id", id);;
             session.setAttribute("login.passwd", passwd);
             session.setAttribute("login.time", new Long(System.currentTimeMillis()));
%>
 
<html>
<body>
<center>
<a href="showinfo.jsp">로그인 정보보기</a>
</body>
</html>
 
showinfo.jsp
 
<%@ page contentType="text/html;charset=euc-kr" session="false"%>
<%
             HttpSession session = request.getSession(false);
             if(session == null){ //세션이 null을 지니면 페이지전화
                           response.sendRedirect("login.html");
                           return;
             }
// 세션 플래그에 해당하는 값 반환
             String name = (String)session.getAttribute("login.name");
             String passwd = (String)session.getAttribute("login.passwd");
             String id = (String)session.getAttribute("login.id");
             Long start = (Long)session.getAttribute("login.time");
             // currentTimeMillis() 현재시간 반환
             long current = System.currentTimeMillis();
             long durantion = current - start.longValue();
             long durantion_min = (durantion/1000)/60;
             long durantion_sec = (durantion/1000)%60;
             String session_durantion =
                                                  ""+durantion_min+"분 "+durantion_sec+"초";
%>
 
로그인정보<hr>
이름: <%= name%><br>
아이디: <%= id%><br>
패스워드: <%= passwd%><br>
세션유지시간: <%= session_durantion%>
<form action="logout.jsp">
<input type="submit" value="로그아웃">
</form>
 
Logout.html
 
<%@ page contentType="text/html;charset=euc-kr" session="false"%>
<%
             HttpSession session = request.getSession(false);
             String name ="";
             if(session != null){
                           name = (String)session.getAttribute("login.name");
                           session.invalidate();  //세션삭제
             }
%>
<%= name%> 정상 로그아웃 되었습니다.<br>
<a href="showinfo.jsp">로긴 정보보기</a>
 
<!--로그아웃 된상태에서 showinfo 를 보려한다면
      showinfo 가 아닌 login.html 이 나올것이다.
      그 이유는 logout 페이지에서 세션을 삭제하기 때문인데
      showinfo 페이지는 널값을 지닌 세션을 받으면 sendRedirecet 를
      이용하여 페이지를 전환시킨다. -->


출처 : http://blog.empas.com/zeroscience/17230751
ref: http://darky.egloos.com/1182608

웹서버는 클라이언트/서버 모델과 웹의 HTTP를 사용하여 웹 페이지가 들어 있는 파일을 사용자들에게 제공하는 프로그램이다. 웹사이트가 운영되고 있는 인터넷상의 모든 컴퓨터들에는 모두 웹서버 프로그램이 설치되어 있다. 가장 보편적인 웹서버들로는 32 비트 윈도우와 유닉스 기반의 운영체계에서 모두 쓸 수 있는 아파치와, 윈도우 NT에 딸려 나오는 IIS, 그리고 넷스케이프엔터프라이즈 서버 등이 있다. 그밖에 네트웨어 운영체계를 쓰는 사용자들을 위한 노벨의 웹서버, 주로 IBM의 OS/390AS/400 고객들을 위한 IBM의 로터스 도미노 서버를 비롯, 다른 웹서버들도 있다.

웹서버들은 흔히 전자우편, FTP 파일의 다운로드, 그리고 웹페이지 구축, 발간 등에 필요한 인터넷 및 인트라넷과 관련된 프로그램들의 커다란 패키지의 일부로서 나온다. 웹서버를 고를 때 고려해야할 사항으로는, 운영체계나 다른 서버들과 얼마나 잘 어울려 동작할 것이냐 하는 것과, 서버 측의 프로그래밍, 퍼블리싱, 검색엔진 등을 처리하는 능력, 그리고 함께 따라오는 구축도구 등이 있다.


 WAS (Web Application Server)
웹과 기업의 기간 시스템 사이에 위치하면서, 웹 기반 분산 시스템 개발을 쉽게 도와주고 안정적인 트랙잰션 처리를 보장해 주는 일종의 미들웨어 소프트웨어 서버.

3계층 웹 컴퓨팅 환경에서 기존 클라이언트/서버 환경의 애플리케이션 서버와 같은 역할을 하며, 클라이언트와 서버 환경에서 트랜잭션 처리및 다른 기존 시스템 간의 애플리케이션 연동을 등을 주된 기능으로 하고 있다.

요즘들어서는 WAS는 주로 데이터베이스 조회나 일반적인 비즈니스 로직에 대한 처리를 위해 다양한 언어로 개발된 인터넷/인트라넷 환경의 소프트웨어로 많이 불리운다. 자바스크립트나 JSP 등과 같은 스크립트 및 서비스들은 대개 최신의 데이터를 검색하기 위해 데이터베이스에 접근하고, 브라우저 또는 클라이언트 프로그램을 통해 사용자들에게 검색 결과를 제공한다.

WAS를 비롯한 애플리케이션 서버들은, 웹서버 즉 HTTP 서버와 같은 컴퓨터를 공유할 수도 있지만 별개의 컴퓨터를 독립적으로 사용하는 경우도 많다. 대규모 사이트에서는, 오히려 WAS와 웹서버 등을 위해 여러 대의 컴퓨터가 동원되기도 한다.
넷스케이프의 Netscape Application Server, Bea의 Weblogic Enterprise, 볼랜드의 Appserver, 그리고 IBM의 Websphere Application Server 등의 WAS 대표적인 제품들이다.


※Web Server와 WAS와 차이※

- Web Server 의 정의 : Web Client(웹 브라우저)에게 컨텐츠를 제공하는 서버, 정적인 HTML이나 jpeg, gif 같은 이미지를 HTTP 프로토콜을 통해 웹 브라우저에게 전송하는 역할

- WAS(Web Application Server)의 정의
   ○ Server 단에서 Application을 동작할 수 있도록 지원함 => Jeus
   ○ 기존 웹 서버와 달리 동적인 요구에 대응하기 위해 적합한 형태로 변화, Web Client(브라우저)에게는 결과값만 전송함.
   ○ Container(컨테이너)라는 용어로 쓰이며, 초창기는 CGI, 그 후에서는 Servlet, , JSP, ASP 등의 프로그램으로 사용됨

- Web Server와 WAS의 구성에 따른 분류
   ○ WAS와 WebServer를 분리하지 않는 경우 
   모든 컨텐츠를 한곳에 집중시켜 웹서버와 WAS의 역할을 동시에 수행, 스위치를 통한 로드 밸러싱, 사용자가 적을 경우 효율적
 
   ○  WAS와 WebServer를 분리한 경우
   웹서버와 WAS의 기능적 분류를 통해 효과적인 분산을 유도, 정적인 데이터는 웹서버에서 처리, 동적인 데이터는 WAS가 처리
 
   ○  WAS 여러개와 WebServer를 분리한 경우
   WAS단을 프리젠테이션 로직와 비즈니스 로직으로 구분하여 구성, 특정 logic의 부하에 따라 적절한 대응할 수 있지만 설계단
   계 유지보수 단계가 복잡해 질 수가 있다.


 WAS 와 Web Server 종류

   ○ WAS 종류
   tomcat, tMax jeus, BEA Web Logic, IBM Webspere, JBOSS,Bluestone, Gemston, inprise, Oracle, PowerTier,Apptivity,
   silverStream
   ○ Web Server 
    IIS, apache, tMax, WebtoB

   - tomcat
       아파치 소프트웨어 재단의 애플리케이션 서버로서, 자바 서블릿을 실행시키고 JSP 코드가 포함되어 있는 웹페이지를 만들
       어준다. 자바 서블릿과 JSP 규격 '참조용 구현'으로 평가되고 있는 톰캣은, 개발자들의 개방적 협력 작업의 산물로 바이너리
       버전과 코어버전 둘 모두를 아파치 웹사이트에서 얻을 수 있다. 톰캣은 자체적으로 보유하고 있는 내부 웹서버와 함께 독립
       적으로 사용 될 수도 있지만 아파치나 넷스케이프 엔터프라이즈 서버, IIS, 마이크로소프트의 PWS 등 다른 웹서버와 함께 사
       용할 수도 있다. 톰캣을 실행시키기 위해서는 jre  1.1  이상에 부합되는 자바 런타입 환경이 필요하다.

[출처] Web Server 와 WAS|작성자

로그 찍는 거 별로 안좋아하는데 로그를 찍어보니까 더 좋은 것 같아요 ^^
게다가 log4j라는 매우 우수한 로그찍는 프로그램이 있습니다.
sysout에서 벗어나봅시다-_-; 습관적으로 sysout을-_-(System.out.println()......-_-)

우선 이클립스에서 프로젝트를 하나 만들어봅시다.
log4j를 받아봅시다.
http://logging.apache.org/log4j/1.2/download.html
1.2버전입니다. 받아서 log4j-1.2.15.jar파일을 라이브러리에 추가합시다.

log4j설정파일을 만들어봅시다.
최상위 폴더에다가 log4j.properties파일을 만듭시다.

 
# Log4j Setting file 
log4j.rootLogger=INFO, console 
 
# Daily file log 
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender 
log4j.appender.logfile.File=D:/mudchobo/Log/glv.log 
log4j.appender.logfile.DatePattern='.'yyyy-MM-dd 
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 
log4j.appender.logfile.layout.ConversionPattern=[%d{HH:mm:ss}][%-5p](%F:%L) - %m%n 
 
# Console log 
log4j.appender.console=org.apache.log4j.ConsoleAppender 
log4j.appender.console.layout=org.apache.log4j.PatternLayout 
log4j.appender.console.layout.ConversionPattern=%-5p %l - %m%n 
 
# log level and appender 
log4j.logger.com.mudchobo=DEBUG, console 
log4j.logger.com.mudchobo.Test=INFO, logfile 

대략 내용을 살펴보면 log4j.rootLogger는 최상위 로거입니다.
모든 INFO레벨이상의 로그는 다 console로 찍겠다는 겁니다.
(레벨에는 DEBUG, INFO, WARN, ERROR, FATAL 순인데, 예를 들어 INFO레벨로 지정해두면 logger.debug로 찍는 로그는 나타나지 않습니다. INFO레벨 이상것만 나타납니다.)

console은 아래 #Console log쪽에 보시면
log4j.appender.console <- 요 이름입니다.
요 console은 자세히보면 ConsoleAppender라는 클래스입니다. 이건 말그대로 콘솔에 로그를 찍어준다는 겁니다. layout에는 PatternLayout을 지정할 수 있는데 저 패턴은 뭐 레벨이 뭐고, 클래스가 뭐고, 메시지찍고 뭐 그런 내용입니다. 검색 고고싱-_-;

그리고, 파일에다가 출력 할 수 있는데, DailyRollingFileAppender클래스를 이용합니다. 이눔은 말그대로 매일매일 다른로그를 사용하게 만듭니다. 로그이름이 위와 같이 glv.log라면, 해당로그가 어제날짜인데 로그를 찍으려고 하면 기존에 있던 파일은 glv.log.2008-04-17 이렇게 바꿔줍니다.

아래부분에 보면 log4j.logger. 다음에 패키지명이나 클래스명을 지정해놓고, 로그레벨과 출력할 로그를 지정할 수 있는데요. 해당 클래스나 패키지의 로그는 저걸로 찍겠다는 겁니다. Test클래스는 logfile로 찍힌다는 겁니다.
그리고, rootLogger가 colsole로 지정되어 있기 때문에 console에도 찍히겠죠? ^^

로그를 찍어봅시다.
TestLogging이라는 프로젝트 이름으로 만듭시다.

Test클래스를 만들어봅시다.
Test.java
 
package com.mudchobo; 
 
import org.apache.log4j.Logger; 
 
public class Test { 
 
 private Logger logger = Logger.getLogger(getClass()); 
  
 public void println() { 
  logger.info("안녕하세요! Test입니다"); 
 } 
} 

Test2클래스를 만들어봅시다.
Test2.java
 
package com.mudchobo; 
 
import org.apache.log4j.Logger; 
 
public class Test2 { 
 
private Logger logger = Logger.getLogger(getClass()); 
  
 public void println() { 
  logger.info("안녕하세요! Test2입니다."); 
 } 
} 

TestLogging클래스를 만들어봅시다. 메인을 만들어야합니다.
 
package com.mudchobo; 
 
public class TestLogging { 
 
 public static void main(String[] args) { 
  Test test = new Test(); 
  Test2 test2 = new Test2(); 
   
  test.println(); 
  test2.println(); 
 } 
} 

자 그럼 콘솔에는
INFO  com.mudchobo.Test.println(Test.java:10) - 안녕하세요! Test입니다.
INFO  com.mudchobo.Test.println(Test.java:10) - 안녕하세요! Test입니다.
INFO  com.mudchobo.Test2.println(Test2.java:10) - 안녕하세요! Test2입니다.
INFO  com.mudchobo.Test2.println(Test2.java:10) - 안녕하세요! Test2입니다.
이렇게 출력이 될 것이고 로그파일에는
[19:56:35][INFO ](Test.java:10) - 안녕하세요! Test입니다.
이것만 출력될 것입니다.
위에 콘솔에 두번 찍힌 이유는 Rootlogger도 찍고, 아래 패키지를 지정한 로그도 찍었기 때문이죠.
그리고, 파일에는 한번만 쓰여진 이유는 파일에 쓰는건
log4j.logger.com.mudchobo.Test=INFO, logfile 여기 이 Test클래스 하나죠-_-;
이상입니다-_-;


'Java' 카테고리의 다른 글

httpsession 을 이용한 로그인 관리  (0) 2010.08.13
Web Server 와 WAS  (0) 2010.07.28
[자바] 로그 사용법 - log4j-1.2.15.jar (마지막 부분 XML 설정방법)  (0) 2010.07.26
Session 관리  (0) 2010.07.26
java.lang.NoSuchMethodError  (0) 2010.07.22

+ Recent posts