.
.
.
    2003³â 9¿ù 9ÀÏ    

Core Java Technologies Tech Tips (2003³â 9¿ù 9ÀÏ)¿¡ ¿À½Å ¿©·¯ºÐÀ» ȯ¿µÇÕ´Ï´Ù. Java 2 Platform, Standard Edition (J2SE)¿¡ ±â¹ÝÇÑ core Java technologies ¿Í APIsÀÇ »ç¿ë¿¡ °üÇÑ ÃֽŠÁ¤º¸¸¦ ¾ò¾î °¡½Ã±â ¹Ù¶ø´Ï´Ù. ÀÌ ±Û¿¡¼­´Â Java 2 SDK, Standard Edition, v 1.4¸¦ »ç¿ëÇÕ´Ï´Ù.

À̹ø È£¿¡¼­´Â,

-SOCKETCHANNELSÀ» ÀÌ¿ëÇØ¼­ ÀÛ¾÷Çϱâ
-AFFINETRANSFORM ÀÌÇØÇϱâ

ÀúÀÚ Daniel H. Steinberg

.
.

SOCKETCHANNELSÀ» ÀÌ¿ëÇØ¼­ ÀÛ¾÷Çϱâ

Web Services API³ª ȤÀº ³ôÀº ¼öÁØÀÇ API±îÁö ´Ù·ï¾ß ÇÏ´Â ³×Æ®¿öÅ· ŽºÅ©¸¦ ÇØ¾ß ÇÒ ÀÏÀÌ »ý±ä´Ù¸é, ¼ÒÄÏÀ» ÀÌ¿ëÇØ¼­ ŽºÅ©¸¦ ÀûÀº ºñ¿ëÀ¸·Î Á» ´õ °£´ÜÇÏ°Ô ¿Ï¼öÇÒ ¼ö ÀÖ´Â ¹æ¹ýÀ» ã¾Æº¸ÀÚ. À̹ø Tech Tip¿¡¼­´Â ³×Æ®¿öũȭ µÈ °£´ÜÇÑ ¾ÖÇø®ÄÉÀ̼ÇÀ» »ý¼ºÇϱâ À§ÇØ java.nio packageÀÇ SocketChannel°ú ServerSocketChannel Ŭ·¡½º¸¦ »ç¿ëÇÏ°Ô µÉ °ÍÀÌ´Ù.

»ç¿ëÀÚ°¡ ƯÁ¤ À¥ ÆäÀÌÁö¸¦ º¸±â À§ÇØ ºê¶ó¿ìÀú¸¦ ¶ç¿ï ¶§, ÆäÀÌÁöÀÇ ¼¼ºÎÁ¤º¸´Â °¨ÃçÁö°Ô µÈ´Ù. ºê¶ó¿ìÀú¸¦ ¿­°í ´ÙÀ½À» ÀÔ·ÂÇÏÀÚ.

http://developer.java.sun.com/developer/JDCTechTips/

°á°úÀûÀ¸·Î, ÀÌ ¿£Æ®¸®´Â »ç¿ëÀÚ¸¦ À¥ »çÀÌÆ®ÀÇ 80Æ÷Æ®¿¡ ¿¬°á½ÃÄÑÁÖ¸ç, º¸°íÀÚ ÇÏ´Â ÆäÀÌÁöÀÇ À̸§À» Æ÷ÇÔÇϴ ƯÁ¤(particular) HTTP ¿ä±¸(request)µµ º¸³»°Ô µÈ´Ù

ÀÚ ÀÌÁ¦ SocketChannelÀ» ÀÌ¿ëÇØ¼­ ´ÙÀ½ÀÇ ¾×¼ÇÀ» ¸í½ÃÀûÀ¸·Î ½ÇÇàÇØº¸ÀÚ. TechTipReaderÇÁ·Î±×·¥Àº ÆäÀÌÁö¸¦ °Ë»öÇϱâ À§Çؼ­ SocketChannel¸¦ »ç¿ëÇÑ´Ù. ÀÌ ÇÁ·Î±×·¥ÀÇ getTips() ¸Þ¼Òµå¸¦ ÁÖ¸ñÇØ¼­ º¸¸é, ¸ÕÀú SocketChannelÀ» ½ÇÇàÇÏ°í ³­ ÈÄ, ±×°ÍÀ» developer.java.sun.comÀÇ 80Æ÷Æ®¿¡ ¿¬°áÇϱâ À§Çؼ­ ÀνºÅϽº¸¦ »ç¿ëÇÏ´Â °ÍÀ» ¾Ë ¼ö ÀÖ´Ù. ±×¸®°í ³ª¼­ JDCTechTips ÆäÀÌÁö¸¦ °Ë»öÇϱâ À§ÇØ Ç¥ÁØ(standard) HTTP "GET"¿ä±¸(request)¸¦ º¸³½´Ù.

¼­¹ö·ÎºÎÅÍÀÇ ÀÀ´äÀÌ standard out¿¡ Ãâ·ÂµÈ´Ù.

   import java.nio.channels.SocketChannel;
   import java.nio.charset.Charset;
   import java.nio.ByteBuffer;
   import java.net.InetSocketAddress;
   import java.io.IOException;

   public class TechTipReader {

      private Charset charset = 
        Charset.forName("UTF-8");
      private SocketChannel channel;

      public void getTips() {
        try {
          connect();
          sendRequest();
          readResponse();
        } catch (IOException e) {
          e.printStackTrace();
        } finally {
          if (channel != null) {
            try {
              channel.close();
            } catch (IOException e) {}
          }
       }
      }

      private void connect() throws IOException {
         InetSocketAddress socketAddress =
           new InetSocketAddress(
             "developer.java.sun.com", 80);
         channel = SocketChannel.open(socketAddress);
       }

      private void sendRequest() throws IOException {
          channel.write(charset.encode("GET "
                            + "/developer/JDCTechTips/"
                            + "\r\n\r\n"));
        }

      private void readResponse() throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while ((channel.read(buffer)) != -1) {
          buffer.flip();
          System.out.println(charset.decode(buffer));
          buffer.clear();
        }
      }

      public static void main(String[] args) {
        new TechTipReader().getTips();
      }
   }

TechTipReader ÇÁ·Î±×·¥À» ÀÚ¼¼È÷ µé¿©´Ùº¸¸é, connect() ¸Þ¼Òµå°¡ InetSocketAddress¸¦ »ý¼ºÇÒ ¶§, µµ¸ÞÀΰú Ç¥ÁØ(standard) HTTP 80Æ÷Æ®¸¦ ³ªÅ¸³»´Â ½ºÆ®¸µ, ÀÌ·¸°Ô µÎ °³ÀÇ ¸Å°³º¯¼ö(parameters)¸¦ ¹Þ°í ÀÖ´Â °ÍÀ» ¹ß°ßÇÏ°Ô µÉ °ÍÀÌ´Ù. ±×¸®°í ½ºÅÂÆ½ ¸Þ¼ÒµåÀÎ SocketChannel.open()À» È£ÃâÇϸé InetSocketAddress¸¦ ¸Å°³º¯¼ö(parameter)·Î °®´Âµ¥, ÀÌ È£ÃâÀº ´ÙÀ½ 2°³ÀÇ °úÁ¤¿¡ »ó´çÇÑ´Ù.

   channel = SocketChannel.open();
   channel.connect(socketAddress);

sendRequest() ¸Þ¼Òµå´Â ù¹øÂ° ¶óÀο¡ "GET /developer/JDCTechTips/", µÎ¹øÂ°¿Í ¼¼¹øÂ° ¶óÀÎÀº ºñ¾îÀÖ´Â3ÁÙÂ¥¸® ¿ä±¸(request)¸¦ º¸³½´Ù. channel.write() È£ÃâÀº ByteBuffer¸¦ Àμö(argument)·Î °®±â ¶§¹®¿¡ »ç¿ëÀÚ´Â ½ºÆ®¸µÀ» º¯È¯ÇØ¾ß ÇÑ´Ù. »ç½Ç SocketChannelsÀ» ÀÌ¿ëÇØ¼­ ÀÛ¾÷ÇÒ ¶§, ByteBuffers¸¦ º¯È¯ÇÏ´Â µ¥¿¡ ´ëºÎºÐÀÇ ½Ã°£À» ÇÒ¾ÖÇÏ°Ô µÈ´Ù. º¯È¯ÇÏ´Â ¹æ¹ý¿¡´Â ¿©·¯ °¡Áö°¡ ÀÖÀ» ¼ö ÀÖÁö¸¸ ÀÌ ¿¹Á¦¿¡¼­´Â java.nio.charset.CharsetŬ·¡½ºÀÇ encode()¸Þ¼Òµå¸¦ »ç¿ëÇÑ´Ù.

readResponse()¸Þ¼Òµå´Â SocketChannel·Î ¸®ÅϵǴ ÀÀ´äÀ» ó¸®ÇÏ´Â ¿ªÇÒÀ» Çϸç, SocketChannelÀ» ÅëÇØ¼­ ByteBuffer¸¦ ÀоîµéÀδÙ. Àü¼ÛµÇ´Â ÆÄÀÏÀÇ ³¡¿¡ µµ´ÞÇÏÁö ¾Ê´Â ÇÑ, readResponse()¸Þ¼Òµå´Â ¹öÆÛ¸¦ Àбâ»óÅ¿¡¼­ ¾²±âÁغñ »óÅ·ΠµÚÁý´Â´Ù. ByteBufferÀÇ ³»¿ëÀº charset.decode()¸Þ¼Òµå¿¡ ÀÇÇØ ½ºÆ®¸µÀ¸·Î º¯È¯µÇ°í, ÀÌ ½ºÆ®¸µÀº standard outÀ¸·Î º¸³»Áø´Ù.

TechTipReader ÇÁ·Î±×·¥À» ½ÇÇàÇÒ ¶§, µð½ºÇ÷¹ÀÌ µÈ ÆäÀÌÁöÀÇ HTMLÀ» ºÁ¾ß ÇÑ´Ù.

ÀÚ ÀÌÁ¦ µÎ ¹øÂ° ¿¹Á¦¸¦ º¸ÀÚ. Ŭ¶óÀÌ¾ðÆ®¿Í ¼­¹ö¸¦ µ¿¹ÝÇÑ ÀÌ ¿¹Á¦¿¡¼­´Â 2°³ÀÇ ¼ýÀÚ°¡ ´õÇØÁø´Ù. Ŭ¶óÀÌ¾ðÆ®°¡ ´õÇØÁú 2°³ÀÇ ¼ýÀÚ¸¦ ¼­¹ö¿¡ º¸³»¸é ¼­¹ö´Â µ¡¼ÀÀ» ¼öÇàÇϰí Çհ踦 ³½´Ù. ÀÌ ¿¹´Â SocketChannel APIÀ» ±â¹ÝÀ¸·Î ÇÏÁö¸¸, À¥¼­ºñ½º³ª RMI ȤÀº ¼­ºí¸´À» ÀÌ¿ëÇÏ´Â ´Ù¸¥ ¼Ö·ç¼Çµµ °¡´ÉÇÏ´Ù.

¿©±â¿¡¼­ ByteBuffer´Â 2°³ÀÇ int°ªÀ» °®´Âµ¥ À̵éÀº »ç¿ëÀÚ°¡ ByteBufferÀ» 8byte·Î Á¦ÇÑÇϰí, ByteBuffer¿¡ ´ëÇÑ ºä(view)ÀÇ ¿ªÇÒÀ» ÇÏ´Â IntBufferÀ» »ý¼ºÇϵµ·Ï ÇÑ´Ù.

  private ByteBuffer buffer = ByteBuffer.allocate(8);
  private IntBuffer intBuffer = buffer.asIntBuffer();

SumClient¶ó´Â ´ÙÀ½ÀÇ ÇÁ·Î±×·¥Àº ¿¹Á¦ÀÇ Å¬¶óÀÌ¾ðÆ®ºÎºÐÀε¥ À̸¦ ½ÇÇàÇϱâ À§Çؼ­´Â ÀÌ ±ÛÀÇ µÞºÎºÐ¿¡¼­ º¸°Ô µÉ ¿¹Á¦ÀÇ ¼­¹öºÎºÐ(SumServer)À» ¸ÕÀú ½ÃÀÛÇØ¾ß ÇÑ´Ù.

   import java.nio.channels.SocketChannel;
   import java.nio.ByteBuffer;
   import java.nio.IntBuffer;
   import java.io.IOException;
   import java.net.InetSocketAddress;

   public class SumClient {

      private SocketChannel channel;
      private ByteBuffer buffer = ByteBuffer.allocate(8);
      private IntBuffer intBuffer = buffer.asIntBuffer();

      public void getSum(int i, int j) {
        try {
          channel = connect();
          sendSumRequest(i, j);
          receiveResponse();
        } catch (IOException e) {
          // add exception handling code here
          e.printStackTrace();
        } finally {
          if (channel != null) {
            try {
              channel.close();
            } catch (IOException e) {
              // add exception handling code here
              e.printStackTrace();
            }
          }
        }
      }

      private SocketChannel connect() 
                                   throws IOException {
        InetSocketAddress socketAddress =
          new InetSocketAddress("localhost", 9099);
        return SocketChannel.open(socketAddress);
      }

      private void sendSumRequest(int i, int j)
                                   throws IOException {
        buffer.clear();
        intBuffer.put(0, i);
        intBuffer.put(1, j);
        channel.write(buffer);
        System.out.println("Sent request for sum of "
                           + i + " and " + j + "...");
      }

      private void receiveResponse() 
                                   throws IOException {
        buffer.clear();
        channel.read(buffer);
        System.out.println(
                       "Received response that sum is "
                       + intBuffer.get(0) + ".");
      }

      public static void main(String[] args) {
        new SumClient().getSum(14, 23);
      }
   }

SumClientÀÇ getSum()¸Þ¼Òµå´Â SocketChannelÀ» ¹Ì¸® ¿¹Á¤µÈ ÁÖ¼Ò·Î ¿¬°áÇÑ´Ù. connect()¸Þ¼Òµå´Â TechTipReader ¿¹Á¦¿¡¼­ º¸¾Ò´ø °Í°ú º»ÁúÀûÀ¸·Î µ¿ÀÏÇÏ´Ù. connect() ¸Þ¼Òµå¸¦ È£ÃâÇϸé, getSum() ¸Þ¼Òµå´Â 2°³ÀÇ int°ª(14, 23)À» Â÷·Ê´ë·Î sendSumRequest() ¸Þ¼Òµå·Î ³Ñ±â´Âµ¥, ÀÌ ¶§ sendSumRequest()´Â ByteBufferÀÇ ³»¿ëÀ» SocketChannel¿¡ ÀÔ·ÂÇÏ´Â ¿ªÇÒÀ» ÇÑ´Ù. ±×·¯¸é receiveResponse() ¸Þ¼Òµå´Â ¸®ÅÏµÈ ¸Þ¼ÒµåÀÇ ³»¿ëÀ» °¡Áö°í ¿Í¼­ ±×°ÍÀ» standard out¿¡ Ãâ·ÂÇÏ°Ô µÈ´Ù.

»ç¿ëÀÚ°¡ SumClient¸¦ ½ÇÇà½Ã۸é, ´ÙÀ½ »çÇ×ÀÌ È­¸é¿¡ Ç¥½ÃµÈ´Ù. (SumServer¸¦ ¸ÕÀú ½ÇÇàÇØ¾ß ÇÏ´Â °ÍÀ» ÀØÁö ¸»ÀÚ.)

   Sent request for sum of 14 and 23...
   Received response that sum is 37.

SumClient¸¦ ÀÚ¼¼È÷ º¸¸é, sendSumRequest()°¡ °°Àº ByteBufferÀÇ 2°³ÀÇ ´Ù¸¥ ºä(view)¸¦ »ç¿ëÇÏ´Â °ÍÀ» ¾Ë ¼ö ÀÖ´Ù. ¸ÕÀú, buffer.clear()´Â »ç½Ç»ó ¹öÆÛ¸¦ ºñ¿ì°í ByteBuffer´Â intBuffer ÇÚµéÀÇ »ç¿ëÀ¸·Î ÀÎÇØ 2°³ÀÇ int°ªÀ» °®´Â ¹öÆÛ·Î °£ÁֵȴÙ. sendSumRequest()ÀÇ Ã¹¹øÂ° ÆÄ¶ó¹ÌÅÍ·Î ³Ñ°ÜÁø int°ªÀº intBuffer.put(0,i)À» ÀÌ¿ëÇÏ¿© ù¹øÂ° ½½·Ô¿¡ ³õ¿©Áö°í, µÎ¹øÂ° ÆÄ¶ó¹ÌÅÍ ¶ÇÇÑ À¯»çÇÑ ¹æ¹ýÀ¸·Î µÎ¹øÂ° ½½·Ô¿¡ ³õ¿©Áø´Ù. SocketChannel ÀÇ write()¸Þ¼Òµå´Â ByteBuffer¸¦ °®±â ¶§¹®¿¡ ¹öÆÛÀÇ Ã¹¹øÂ° ºä(view)°¡ ÇÊ¿äÇÏ´Ù.

receiveResponse()¸Þ¼Òµå´Â sendSumRequest()¿Í °°´Ù(parallel). ¹öÆÛÀÇ ³»¿ëÀÌ ¶Ç´Ù½Ã ºñ¿öÁö°í SocketChannelÀÇ ³»¿ëÀº ¹öÆÛÀÇ ByteBuffer ºä(view)·Î ÇØ¼®µÈ´Ù. IntBuffer´Â ù¹øÂ° À§Ä¡¿¡¼­ int°ªÀ» µµÃâÇϱâ À§ÇØ »ç¿ëµÈ´Ù.

¼Ö·ç¼ÇÀÇ ¼­¹öºÎºÐÀÎ SumServer·Î ³Ñ¾î°¡±â Àü¿¡, SocketChannel °´Ã¼ÀÇ read() ¿Í write() ¸Þ¼Òµå¸¦ È£ÃâÇÏ´Â Àå¼Ò¿¡ Ãß°¡ÀûÀÎ ¾ÈÀüÀåÄ¡¸¦ ³Ö±æ ¿øÇÒ ¼öµµ ÀÖ´Ù. ÀÌ ¸Þ¼ÒµåµéÀº ÀÐÈ÷°Å³ª ȤÀº ÀԷµǴ ¹ÙÀÌÆ®ÀÇ ¼ö¿Í ÇÔ²² long°ªÀ» ¸®ÅÏÇϴµ¥, À̹øÀÇ °æ¿ì¿¡´Â 8¹ÙÀÌÆ®¶ó°í »ý°¢ÇÏ¸é µÈ´Ù. sendSumRequest()ÀÇ ´ÙÀ½ ¶óÀÎÀ» ã¾Æº¸°í:

   channel.write(buffer);

ÀԷµǴ ¹öÆÛÀÇ »çÀÌÁ È®ÀÎÇÏ´Â ´ÙÀ½ÀÇ ³»¿ëÀ¸·Î ¹Ù²ÙÀÚ.

   if (channel.write(buffer)!= 8){
       throw new IOException("Expected 8 bytes.");
}

receiveResponse()¸Þ¼ÒµåÀÇ channel.read() È£ÃâÁÖº¯¿¡ ºñ½ÁÇÑ °¡µå¸¦ ³ÖÀÚ.

ÀÌÁ¦ SumServer¸¦ º¸ÀÚ. ÀÌ ¿¹Á¦¸¦ ½ÇÇàÇϱâ À§Çؼ­, »ç¿ëÀÚ´Â µ¿ÀÇÇÑ À§Ä¡¿¡ Âø½Å¿ä±¸(incomingrequest)¸¦ ó¸®ÇÏ°Ô µÉ ¼­¹ö¸¦ ¼Â¾÷ÇØ¾ß ÇÑ´Ù. ¹ØÀÇ openChannel() ¸Þ¼Òµå¿¡¼­´Â 9099Æ÷Æ®°¡ »ç¿ëµÇ¾ú´Ù. ServerSocketChannelÀÇ static methodÀÎ open()ÀÌ È£ÃâµÇ¸é, ±× ´ÙÀ½ ¶óÀÎÀº ¸í½ÃµÈ Æ÷Æ®¿¡ ¼ÒÄÏÀ» ¹­´Â´Ù. ±×¸®°í channel.isOpen() ¸Þ¼Òµå°¡ Æ®·ç(true)¸¦ ¸®ÅÏÇϴ´ë·Î È®Àθ޽ÃÁö°¡ standard outÀ¸·Î º¸³»Áø´Ù.

   import java.nio.ByteBuffer;
   import java.nio.IntBuffer;
   import java.nio.channels.ServerSocketChannel;
   import java.nio.channels.SocketChannel;
   import java.io.IOException;
   import java.net.InetSocketAddress;

   public class SumServer {

      ByteBuffer buffer = ByteBuffer.allocate(8);
      IntBuffer intBuffer = buffer.asIntBuffer();
      ServerSocketChannel channel = null;
      SocketChannel sc = null;

      public void start() {
        try {
          openChannel();
          waitForConnection();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      private void openChannel() throws IOException {
        channel = ServerSocketChannel.open();
        channel.socket().bind(
                          new InetSocketAddress(9099));
        while (!channel.isOpen()) {
        }
        System.out.println("Channel is open...");
      }

      private void waitForConnection() 
      throws IOException {
        while (true) {
          sc = channel.accept();
          if (sc != null) {
            System.out.println(
                           "A connection is added...");
            processRequest();
            sc.close();
          }
        }
      }

      private void processRequest() throws IOException {
        buffer.clear();
        sc.read(buffer);
        int i = intBuffer.get(0);
        int j = intBuffer.get(1);
        buffer.flip();
        System.out.println("Received request to add "
                           + i + "  and " + j);
        buffer.clear();
        intBuffer.put(0, i + j);
        sc.write(buffer);
        System.out.println("Returned sum of " +
                           intBuffer.get(0) + ".");
      }

      public static void main(String[] args) {
        new SumServer().start();
      }

   }

»ç¿ëÀÚ°¡ SumServer¸¦ ½ÃÀÛÇϸé, ´ÙÀ½ ¸Þ½ÃÁö°¡ ³ªÅ¸³­´Ù.

   Channel is open...

   Sent request for sum of 14 and 23...
   Received response that sum is 37.  

SumClient¸¦ ½ÇÇà½Ã۸é, SumServer´Â ÀÌÇÏÀÇ ³»¿ëÀ» È­¸é¿¡ Ç¥½ÃÇÑ´Ù.

   
   A connection is added...
   Received request to add 14  and 23
   Returned sum of 37. 

waitForConnection() ¸Þ¼Òµå¿¡¼­´Â ServerSocketChannel¿¡ Á¢¼ÓÇÏ·Á´Â ¿ä±¸°¡ µµÂøÇÒ ¶§±îÁö ¾ÖÇø®ÄÉÀ̼ÇÀÌ Áֱ⸦ °®°í ¹Ýº¹ÇÑ´Ù. ÀÌ ¿ä±¸°¡ ÃæÁ·µÇ¸é, channel.accept()´Â SocketChannelÀ» ¸®ÅÏÇϱ⠶§¹®¿¡ º¯¼ö sc´Â ´õ ÀÌ»ó nullÀÌ ¾Æ´Ï´Ù. Âø½Å¿ä±¸(incoming request)°¡ 󸮵Ǹé SocketChannel´Â Á¾·áµÇ°í, ¼­¹ö´Â ´Ù½Ã SumServer¸¦ ½ÃÀÛÇØ¼­ ´Ù¸¥ Á¢¼Ó¿äûÀ» ´ë±âÇÑ´Ù. ÀÌ °£´ÜÇÑ ¿¹Á¦¿¡¼­ ¿ä±¸(requests)µéÀº Çѹø¿¡ ¿ÏÀüÈ÷ 󸮵ȴٴ °ÍÀ» »ó±âÇÏÀÚ. µ¿½Ã´Ù¹ßÀûÀÎ ¿ä±¸¸¦ ¼öÇàÇÒ ¼ö ÀÖ´Â Á» ´õ ½ÉÈ­µÈ ¼­¹ö¸¦ À§Çؼ­´Â ´Ù¸¥ ±¸Á¶°¡ ÇÊ¿äÇÏÁö¸¸, À̰ÍÀº À̹ø Å×Å©ÆÁÀÌ Ä¿¹öÇÏ´Â ¹üÀ§¸¦ ¹þ¾î³ª±â ¶§¹®¿¡ ´Ù·çÁö ¾Ê°Ú´Ù.

processRequest() ¸Þ¼Òµå´Â SumClientÀÇ ´ëÀÀ ¸Þ¼Òµå(corresponding methods)¿Í ¸Å¿ì Èí»çÇÏ´Ù. ¹öÆÛ°¡ Áö¿öÁö¸é ä³ÎÀÌ ¹öÆÛ·Î ÀÐÇôÁö°í IntBuffer ºä(view)´Â ¹öÆÛ¿¡¼­ ÆÄ»ýµÈ 2°³ÀÇ int°ªÀ» °Ë»öÇϴµ¥ »ç¿ëµÈ´Ù. »ç¿ë ÈÄ ¹öÆÛ°¡ Á¦°ÅµÇ°í ÇÕ°è´Â IntBuffer ºä(view)ÀÇ »ç¿ë Áß¿¡ ·ÎµåµÇ´Âµ¥, ±×¸®°í ³ª¼­ ¹öÆÛ´Â SocketChannel·Î ´Ù½Ã ¾²¿©Áö°Ô µÈ´Ù. SocketChannel°üÇÑ ÀÚ¼¼ÇÑ Á¤º¸´Â Å×Å©´ÏÄà ¾ÆÆ¼Å¬ÀÎ "New I/0 Functionality for Java 2 Standard Edition 1.4"À» Âü°íÇÑ´Ù.

.
.

AFFINETRANSFORM ÀÌÇØÇϱâ

»ç¿ëÀÚ°¡ À¯»çº¯È¯(affine transformation)À» ¼öÇàÇÒ ¼ö ÀÖµµ·Ï ÇØÁÖ´Â java.awt.geom.AffineTransformŬ·¡½º´Â Java 2D Ŭ·¡½º¿¡ ¼ÓÇÑ´Ù. À¯»çº¯È¯Àº 2Â÷¿ø À̹ÌÁöÀÇ ÁÂÇ¥¸¦ ÆòÇ༱ÀÌ ÆòÇàÀ» À¯ÁöÇÏ´Â °Í°ú °°Àº ¹æ¹ýÀ¸·Î º¯È¯ÇÑ´Ù. °¡·É, »ç¿ëÀÚ°¡ Á÷»ç°¢ÇüÀ¸·Î ½ÃÀÛÇÏ´õ¶óµµ, À¯»çº¯È¯À» ÀÌ¿ëÇØ¼­ ´Ù¸¥ À§Ä¡¿¡ ÆòÇà»çº¯ÇüÀ» »ý¼ºÇÒ ¼ö°¡ ÀÖ´Ù. À̶§¿¡ ¶óÀÎÀº ¶óÀÎÀ» ³²±â¸é¼­ ÆòÇà°ü°è´Â À¯ÁöµÇ°Ô µÈ´Ù. À¯»çº¯È¯À» ÀÌ¿ëÇÏ¸é º¯È¯(translations), ȸÀü(rotations), (Çø³À» Æ÷ÇÔÇÑ) Å©±âÁ¶Á¤(scaling), Àü´Ü(shears)ÀÌ °¡´ÉÇÏ´Ù.

AffineTransformÀÇ documentationÀ» º¸¸é,

 
 ±×·¯ÇÑ ÁÂÇ¥º¯È¯Àº ¸¶Áö¸· Çà¿¡ [0 0 1]À» ¼ö¹ÝÇÏ´Â 3Çà3¿­ ¸ÅÆ®¸¯½º·Î ³ªÅ¸³¾ ¼ö°¡ ÀÖ´Ù. 
ÀÌ ¸ÅÆ®¸¯½º´Â ¿ø½ÃÁÂÇ¥(source coordinates)¿Í ¸ñÀûÁÂÇ¥(destination coordinates)¸¦ 
¿­º¤ÅÍ(column vector)·Î ¸¸µç ÈÄ ´ÙÀ½°ú °°ÀÌ ¸ÅÆ®¸¯½º¸¦ ÁÂÇ¥º¤ÅÍ¿¡ °öÇØ°¡´Â ¹æ¹ýÀ¸·Î 
¿ø½ÃÁÂÇ¥(x,y)¸¦ ¸ñÀûÁÂÇ¥ÀÎ (x',y')·Î º¯È¯ÇÑ´Ù.

   [ x']   [ m00  m01  m02 ]  [ x ]   [ m00x + m01y + m02 ]
   [ y'] = [ m10  m11  m12 ]  [ y ] = [ m10x + m11y + m12 ]
   [ 1 ]   [  0    0    1  ]  [ 1 ]   [         1         ]

À̹ø Å×Å©ÆÁ¿¡¼­´Â »ç¿ëÀÚ°¡ 2Â÷¿ø °ø°£ÀÇ À¯»çº¯È¯À» Ç¥ÇöÇϱâ À§Çؼ­ 3Çà3¿­ ¸ÅÆ®¸¯½º¸¦ ÀÌ¿ëÇØ¾ß ÇÏ´Â ÀÌÀ¯¸¦ ¼³¸íÇϸ鼭, ±âº»º¯È¯À» À§ÇÑ ¸ÅÆ®¸¯½º¸¦ AffineTransform Ŭ·¡½º¿¡¼­ÀÇ ÇÔ¼öÈ£Ãâ°ú ¿¬°ü½Ã۰íÀÚ ÇÑ´Ù.

ÀÌ ±Û¿¡¼­´Â »ç¿ëÀÚ°¡ AffineChecker¶ó´Â ´ÙÀ½ÀÇ ÇÁ·Î±×·¥À» ½ÇÇà½ÃŰ¸é¼­ AffineTransformº¯È¯À» Çà·ÄÀÇ °ö(matrix multiplications)°ú ºñ±³ÇÏ°Ô µÉ °ÍÀÌ´Ù. ÀÌ ÇÁ·Î±×·¥¿¡¼­ Point2D.DoubleÀÇ 3°³ ÀνºÅϽº º¯¼öµéÀ» Àß º¸¾ÆµÎÀÚ. ÀÌ º¯¼öµéÀº (2,3)ÀÇ ÁÂÇ¥¸¦ °®´Â ½ÃÀÛÁ¡°ú °¢°¢ÀÇ º¯È¯À¸·ÎºÎÅÍ »ý±ä Á¡µé¿¡ ÇØ´çÇÑ´Ù.

   import java.awt.geom.Point2D;
   import java.awt.geom.AffineTransform;

   public class AffineChecker {
      private static Point2D startingPoint
                             = new Point2D.Double(2,3);
      private static Point2D affineResult
                               = new Point2D.Double();
      private static Point2D matrixResult
                               = new Point2D.Double();

      public static void matrixMultiply(
                               double m00, double m01,
                               double m10, double m11){
        double x = m00 * startingPoint.getX() +
                   m01 * startingPoint.getY();
        double y = m10 * startingPoint.getX() +
                   m11 * startingPoint.getY();
        matrixResult.setLocation(x,y);
      }

      public static void perform(AffineTransform at){
        at.transform(startingPoint,affineResult);
      }

      public static void report(){
        System.out.println("Affine Result = ("
                          + affineResult.getX() + " , "
                          + affineResult.getY() + ")");
        System.out.println("Matrix Result = ("
                          + matrixResult.getX() + " , "
                          + matrixResult.getY() + ")");
        if (affineResult.distance(matrixResult)<.0001){
          System.out.println("    No real difference");
        }
      }
   }

AffineCheckerÀÇ matrixMultiply() ¸Þ¼Òµå´Â Ç¥ÁØ Çà·ÄÀÇ °ö(standard matrix multiplication)À» º¸¿©ÁØ´Ù.

   [ m00 m01 ] [ x ]   [ m00x + m01y]
   [ m10 m11 ] [ y ] = [ m10x + m11y]

ÀÌ ÇÁ·Î±×·¥ÀÇ report()¸Þ¼Òµå´Â º¯È¯ÀÇ °á°ú¿Í Çà·ÄÀÇ °ö(matrix multiplication)ÀÇ °á°ú°ªÀ» Ãâ·ÂÇϰí, °á°úµéÀÌ º»ÁúÀûÀ¸·Î °°´Ù°í º¼ ¼ö ÀÖÀ» ¸¸Å­ ÃæºÐÈ÷ °¡±î¿îÁö¸¦ ºñ±³ÇÑ´Ù.

ù¹øÂ° Å×½ºÆ®·Î, ½ÃÀÛÁ¡¿¡ ¾Æ¹«°Íµµ ÇÏÁö¸»°í ºñ±³¸¦ ÇØº¸ÀÚ. À̸¦ À§ÇØ ´ÙÀ½ ÇÁ·Î±×·¥À» µ¹·Áº»´Ù.

   import java.awt.geom.AffineTransform;

   public class NothingChecker {
      public static void main(String[] args){
        System.out.println(
                       "The result of doing nothing:");
        AffineChecker.perform(
          AffineTransform.getRotateInstance(0));
        AffineChecker.matrixMultiply(1,0,
                                     0,1);
        AffineChecker.report();
      }
   }

NothingChecker´Â »õ·Î¿î ȸÀüº¯È¯À» »ý¼ºÇϰí, ½ºÅÂÆ½ ¸Þ¼Òµå È£ÃâÀ» ÀÌ¿ëÇØ¼­ ȸÀüµÇ±â À§Çؼ­ °¢µµ(degree)¸¦(ÀÌ ¿¹Á¦ÀÇ °æ¿ì¿£ 0) ³Ñ°ÜÁØ´Ù.

   AffineTransform.getRotateInstance(0)

±×¸®°í ³ª¼­ NothingChecker´Â AffineCheckerÀÇ perform() ¸Þ¼Òµå¸¦ ÅëÇØ transform()À» ¸®ÅÏµÈ AffineTransform¿¡ È£ÃâÇÑ´Ù. ¿©±â¼­ ÁÖ¸ñÇÒ ¸¸ÇÑ °ÍÀº Á¡(2,3)À» º¯È¯Çϰí affineResult¿¡ °á°úÁ¡(resulting point)À» ÀúÀåÇϱâ À§ÇØ startingPoint °ú affineResult¸¦ transform()¸Þ¼Òµå¿¡ ³Ö¾îÁÖ°í ÀÖ´Ù´Â °ÍÀÌ´Ù. ´ÙÀ½À¸·Î NothingChecker´Â Affine Result¸¦ 2Çà2¿­ Ç×µîÇà·Ä(identity matrix)À» °öÇÑ °ª°ú ºñ±³ÇÑ´Ù.

  [ 1 0 ]
  [ 0 1 ]

NothingCheckerÀ» ½ÇÇà½Ãų ¶§, »ç¿ëÀÚ´Â ÀÌÇÏÀÇ ³»¿ëÀ» º¸°Ô µÇ°í,

   The result of doing nothing:
   Affine Result = (2.0 , 3.0)
   Matrix Result = (2.0 , 3.0)
       No real difference

»ç¿ëÀÚ´Â µÎ º¯È¯ÀÇ °á°ú°¡ ¸ðµÎ Á¡(2,3)À̶ó´Â °ÍÀ» ¹ß°ßÇÏ°Ô µÈ´Ù.

x¿Í y¹æÇâÀ¸·ÎÀÇ Å©±âÁ¶Á¤Àº AffineTransformÀÇ ½ºÅÂÆ½ ¸Þ¼ÒµåÀÎ getScaleInstance()À» ÀÌ¿ëÇÑ´Ù. X¹æÇâÀ¸·Î 4, y ¹æÇâÀ¸·Î 5, ÀÌ·¸°Ô µÎ ¿ä¼Ò¸¦ »ðÀÔÇÏ¿© Å©±âÁ¶Á¤À» ÇØº¸ÀÚ. ¿©±â Å©±âÁ¶Á¤ÀÇ ¹æ¹ýÀ» º¸¿©ÁÖ´Â Çà·ÄÀÇ °ö(matrix multiplication)ÀÌ ÀÖ´Ù.

  [ 4 0 ]  [ x ]   [ 4x ]
  [ 0 5 ]  [ y ] = [ 5y ].

´ÙÀ½ÀÇ ÇÁ·Î±×·¥Àº getScaleInstance() È£ÃâÀ» º¸¿©Áִµ¥, »ç¿ëÀÚ´Â º¯È¯°ú Çà·ÄÀÇ °ö(matrix multiplication)À» ºñ±³Çϱâ À§ÇØ ´ÙÀ½ ÇÁ·Î±×·¥À» ½ÇÇàÇÒ ¼ö ÀÖ´Ù.

   import java.awt.geom.AffineTransform;

   public class Scale4Xand5YChecker {
      public static void main(String[] args) {
        System.out.println(
                       "The results of scaling four " +
                       "times in the x direction " +
                       "and five times in the y:");
        AffineChecker.perform(
          AffineTransform.getScaleInstance(4,5));
        AffineChecker.matrixMultiply(4,0,
                                     0,5);
        AffineChecker.report();
      }
   }

°á°ú´Â ´ÙÀ½°ú °°´Ù.

 
   The results of scaling four times in the x direction and five 
   times in the y:
   Affine Result = (8.0 , 15.0)
   Matrix Result = (8.0 , 15.0)
       No real difference

°á°ú°ªÀÌ ¶Ç ´Ù½Ã °°Àº °ÍÀ» º¼ ¼ö ÀÖ´Ù.

»ç¿ëÀÚ´Â Å©±âÁ¶Á¤ °è¼ö ÁßÀÇ Çϳª¿¡ À½¼ö¸¦ ³Ö¾îº½À¸·Î½á x¿Í yÃà¿¡ ´ëÇØ¼­ ÀÌÇØÇÒ ¼ö°¡ Àִµ¥, ¿¹¸¦ µé¸é,

  [ -1 0 ]  [ x ]   [ -x ]
  [  0 1 ]  [ y ] = [  y ]

¿©±â¿¡¼­ x¹æÇâÀÇ °ªÀÌ ¹Ù²ï °ÍÀ» º¼ ¼ö ÀÖ´Ù. ¹ØÀÇ ÇÁ·Î±×·¥¿¡¼­´Â À§ÀÇ °ªÀ» ³Ö¾î ¼öÇàÇÏ°í ±×°ÍÀ» Çà·ÄÀÇ °ö(matrix multiplication)°ú ºñ±³Çϰí ÀÖ´Ù.

   import java.awt.geom.AffineTransform;

   public class FlipChecker {
      public static void main(String[] args) {
         System.out.println(
                       "The results of flipping over" +
                       "the y-axis:");
       AffineChecker.perform(
          AffineTransform.getScaleInstance(-1,1));
        AffineChecker.matrixMultiply(-1, 0,
                                     0, 1);
        AffineChecker.report();
      }
   }

°á°ú´Â,

   The results of flipping over the y-axis:
   Affine Result = (-2.0 , 3.0)
   Matrix Result = (-2.0 , 3.0)
       No real difference   

ȸÀüÀ» ½Ã۱â À§Çؼ± µð±×¸®(degree)°¡ ¾Æ´Ñ ¶óµð¾È(radian)ÀÎ Àμö(argument)¸¦ ³Ö¾î Áà¾ß ÇÑ´Ù. ¹°·Ð ÀÌ¹Ì ¾Ë°í ÀÖ°ÚÁö¸¸, µð±×¸®´Â pi¸¦ °öÇϰí À̰ÍÀ» 180µð±×¸®·Î ³ª´®À¸·Î½á ¶óµð¾ÈÀ¸·Î ½±°Ô ÀüȯÇÒ ¼ö°¡ ÀÖ´Ù. ¿¹¸¦ µé¸é 30µµ´Â pi/6°ú °°°í, Pi/6¶óµð¾È¸¸Å­ ȸÀü½Ã۱â À§Çؼ­´Â ´ÙÀ½°ú °°Àº ȸÀüÇà·Ä (rotation matrix)À» °öÇÑ´Ù.

  [ cos pi/6  -sin pi/6 ]
  [ sin pi/6   cos pi/6 ]

»ç¿ëÀڴ ȸÀüÇà·Ä(rotation matrices)ÀÇ °áÁ¤¿ä¼Ò°¡ 1À̶ó´Â °ÍÀ» »ý°¢ÇØ ³¾ ¼ö°¡ ÀÖ´Ù. ÀÌÇÏ¿Í °°Àº ¹æ¹ýÀ¸·Î °á°ú¸¦ üũÇÏÀÚ.

   import java.awt.geom.AffineTransform;

   public class RotateThirtyChecker {
      public static void main(String[] args) {
        System.out.println(
            "The results of a thirty degree"
            + " counter clockwise rotation:");
        AffineChecker.perform(
          AffineTransform.getRotateInstance(
                                           Math.PI/6));
        AffineChecker.matrixMultiply(
            Math.cos(Math.PI/6), -Math.sin(Math.PI/6),
            Math.sin(Math.PI/6),  Math.cos(Math.PI/6));
        AffineChecker.report();
      }
   }

RotateThirtyCheckerÀ» ½ÇÇàÇÏ¸é ´ÙÀ½°ú °°Àº °á°ú¸¦ ¾òÀ» ¼ö ÀÖ´Ù.

   The results of a thirty degree counter clockwise 
   rotation:
   Affine Result = 
              (0.23205080756887764 , 3.598076211353316)
   Matrix Result = 
              (0.23205080756887764 , 3.598076211353316)
       No real difference   

Àü´Üº¯È¯Àº º¯È¯µÈ °´Ã¼ÀÇ ÇüŸ¦ ¹Ù²Û´Ù. °è¼ö shx´Â yÁÂÇ¥ÀÇ ¿ä¼Ò·Î¼­ x ¹æÇâ(direction)ÀÇ º¯È­·®À», shy´Â xÁÂÇ¥ÀÇ ¿ä¼Ò·Î¼­ y ¹æÇâ(direction)ÀÇ º¯È­·®À» ³ªÅ¸³»´Âµ¥, À̰ÍÀÌ ¹Ù·Î Á÷»ç°¢ÇüÀ» ÆòÇà»çº¯ÇüÀ¸·Î ¹Ù²Ù´Â º¯È¯À̰í Çà·ÄÀÇ ÇüÅ´ ´ÙÀ½°ú °°´Ù.

[  1  shx ]  [ x ]   [ x + y (shx) ]
[ shy  1  ]  [ y ] = [ y + x (shy) ].

º¯È¯À» ÇÏ°í ±×°ÍÀ» Çà·ÄÀÇ °ö(matrix multiplication)°ú ºñ±³ÇÏ´Â ÄÚµå´Â ´ÙÀ½°ú °°´Ù.

   import java.awt.geom.AffineTransform;

   public class ShearChecker {
      public static void main(String[] args) {
         System.out.println(
            "The results of shearing:");
          AffineChecker.perform(
            AffineTransform.getShearInstance(5,6));
          AffineChecker.matrixMultiply(1, 5,
                                       6, 1);
          AffineChecker.report();
      }
   }

ShearCheckerÀ» ½ÇÇàÇϸé,

   
   The results of shearing:
   Affine Result = (17.0 , 15.0)
   Matrix Result = (17.0 , 15.0)
       No real difference

ÀÌÁ¦ ³²¾ÆÀÖ´Â °ÍÀº °íÁ¤·®¿¡ ÀÇÇØ ÇüŸ¦ ¿Å±â´Â °¡Àå ½¬¿î º¯È¯ÀÌ´Ù. x¹æÇâÀÇ tx¿Í y ¹æÇâÀÇ ty¸¦ ¿òÁ÷À̱â À§ÇØ ´ÙÀ½ µ¡¼ÀÀ» ¼öÇàÇÏÀÚ.

  [ tx ]   [ x ]   [ tx + x ]
  [ ty ] + [ y ] = [ ty + y ].

ÇÏÁö¸¸ ¹®Á¦´Â Áö±Ý±îÁö ¸ðµç º¯È¯À» 2Çà2¿­ ¸ÅÆ®¸¯½ºÀÇ °ö¼ÀÀ¸·Î Ç¥ÇöÇß´Ù´Â °ÍÀÌ´Ù. ¶§¹®¿¡ À§ÀÇ ¸ÅÆ®¸¯½º¸¦ ÀÌÁ¦±îÁöÀÇ ¾ÆÀ̵ð¾î¿¡ ÃæÁ·Çϵµ·Ï ¸¸µå´Â ÇѰ¡Áö ¹æ¹ýÀº ¸ðµç º¯È¯µéÀ» ´ÙÀ½°ú °°ÀÌ Àû´Â °ÍÀÌ´Ù.

  [ m00 m01 ] [ x ]   [ tx ]   [ m00x + m01y + tx ]
  [ m10 m11 ] [ y ] + [ ty ] = [ m10x + m11y + ty ]

¿©±â¿¡¼­ ´ÙÀ½°ú °°Àº 3¹øÂ° ÇàÀ» Ãß°¡ ½ÃŰ¸é »ç¿ëÀÚ´Â ÁÂÃøÀÇ ³»¿ëÀ» Á» ´õ °£´ÜÇÏ°Ô ÀûÀ» ¼ö ÀÖÀ» °ÍÀÌ´Ù.

  [ m00  m01  tx ]  [ x ]   [ m00x + m01y + tx ]
  [ m10  m11  ty ]  [ y ] = [ m10x + m11y + ty ]
  [  0    0    1 ]  [ 1 ]   [         1        ]

ÀÌ»óÀÇ ¸ðµç ±¸¼º¿ä¼Òº¯È¯(building block transformations)Àº 6°³ÀÇ °è¼ö m00, m01, m10, m11, tx, and ty, ·Î ȯ»êÇÏ¿© ¾²¿©Áú ¼ö ÀÖ´Ù. (¼ø¼­¿¡ ÁÖÀÇÇÏÀÚ.) À̰ÍÀº ¿ÞÂÊ À§ÀÇ 2Çà2¿­ ¸ÅÆ®¸¯½º¸¦ Àû¿ëÇØ¼­ À̵¿À» ¼öÇàÇÑ °Í¿¡ ÇØ´çÇÑ´Ù. ´ÙÀ½ÀÇ ¸Þ¼Òµå¸¦ AffineChecker¿¡ Ãß°¡ÇÏÀÚ.

   private static void translate(double tx, double ty){
        matrixResult.setLocation(
                             matrixResult.getX() + tx,
                             matrixResult.getY() + ty);
   }

   public static void matrixTransform(
                                double m00, double m01,
                                double m10, double m11,
                                double tx,  double ty){
      matrixMultiply(m00,m01,m10,m11);
      translate(tx,ty);
   }

ÀÚ, ÀÌÁ¦ matrixTransform()¸¦ »ç¿ëÇÏ¸é ¾î¶² º¯È¯ÀÌ¶óµµ È£ÃâÇÒ ¼ö°¡ ÀÖ´Ù. °¡·É, ShearChecker¿¡¼­ matrixMultiply(1,5,6,1) È£ÃâÀ» »õ·Î¿î ¸Þ¼ÒµåÀÎ matrixTransform(1,5,6,1,0,0) È£Ãâ·Î ´ëüÇÒ ¼ö°¡ ÀÖ´Ù´Â °ÍÀÌ´Ù. »Ó¸¸ ¾Æ´Ï¶ó ´ÙÀ½°ú °°Àº ¹æ¹ýÀ¸·Î matrixTransform() ¸Þ¼Òµå¸¦ È£ÃâÇÒ ¼öµµ ÀÖ´Ù.

   import java.awt.geom.AffineTransform;

   public class TranslationChecker {
      public static void main(String[] args) {
         System.out.println("The results of translating " +
                           "by (-2,5):");
        AffineChecker.perform(
          AffineTransform.getTranslateInstance(-2,5));
        AffineChecker.matrixTransform(1,0,0,1,-2,5);
        AffineChecker.report();
      }
   }

TranslationCheckerÀ» ½ÇÇàÇÏ¸é ´ÙÀ½°ú °°Àº °á°ú¸¦ ¾ò°Ô µÈ´Ù.(À§¿¡¼­ ¼³¸íÇÑ 2°³ÀÇ ÇÔ¼ö°¡ AffineChecker¿¡ Ãß°¡µÇ¾ú´ÂÁö È®ÀÎÇÏÀÚ.)

   The results of translating by (-2,5):
   Affine Result = (0.0 , 8.0)
   Matrix Result = (0.0 , 8.0)
       No real difference

ÀÌ·¯ÇÑ ±âº»ÀûÀÎ ¿¬»êÀ» °áÇÕÇØ¼­ AffineTransformŬ·¡½ºÀÇ °£ÆíÇÑ ¸Þ¼Òµå¾È¿¡ Æ÷ÂøµÇ´Â º¹ÀâÇÑ °á°ú°ªÀ» ¾ò¾î³¾ ¼ö ÀÖ´Ù.

AffineTransform¿¡ ´ëÇÑ ´õ ÀÚ¼¼ÇÑ Á¤º¸´Â ÀÚ¹ÙÆ©Å丮¾ó "Transforming Shapes, Text, and Images"¿¡¼­ ãÀ» ¼ö ÀÖ´Ù.

.
.
.

Reader Feedback

  ¸Å¿ì ÁÁ´Ù    ÁÁ´Ù    ±×Àú ±×·¸´Ù 

 

ÀÚ¹Ù ÇÁ·Î±×·¡¹ÖÀÌ ±Ã±ÝÇϼ¼¿ä? Java Online SupportÀ» Âü°íÇϼ¼¿ä.

.
.


Sun Microsystems, Inc.
.
.