| 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"¿¡¼ ãÀ» ¼ö ÀÖ´Ù.
|