16 네트워크 O b j e c t i v e s TCP/IP 프로토콜의개념을이해한다. 자바의소켓포트의개념을이해한다. 서버클라이언트통신프로그램의구조를이해한다. 서버소켓과클라이언트소켓을구분하여이해한다. URL 객체와 URLConnection 객체를활용할줄안다. 소켓프로그래밍을이해한다. 간단한채팅프로그램소스를통해소켓통신을이해한다.
C H A P T E R JAVA PROGRAMMING 네트워크 16.1 TCP/IP TCP/IP 프로토콜소개 TCP 프로토콜 IP(Internet Protocol) 프로토콜 TCP 프로토콜은 Transmission Control Protocol의약자로다른두시스템간에신뢰성있는데이터의전송을관장하는통신프로토콜로서 IP(Internet Protocol) 프로토콜위에서동작한다. TCP 프로토콜을사용하는응용프로그램으로는 e-mail, FTP, 웹 (HTTP) 등이있다. IP는패킷교환네트워크에서송신호스트와수신호스트가데이터를주고받는것을관장하는프로토콜로서 TCP의하위레벨프로토콜이다. TCP/IP 프로토콜및 e-mail, 웹응용프로그램의관계는 [ 그림 16-1] 과같다. 응용프로그램 (HTTP, e-mail, FTP 등 ) Transport (TCP, ) Network (IP, ) Link ( 디바이스 드라이버, ) [ 그림 16-1] 네크워크계층 IP 주소 IP 주소 IP 주소는네트워크상에서유일하게식별될수있는네트워크장치의주소로서, 예를들면 192.156.11.15와같이4개의숫자가. 으로연결된다. 하나의숫자범위는 0~255로서한바이트로표현이가능하다. IP 주소는마치전화번호나집주소와같아이주소를통해네트워크에연결되어있는장치를식별할수있으며, 동일한주소를
제 16 장네트워크 787 16CHAPTER 여러네트워크장치에중복해서사용할수없다. 숫자로된주소는기억하기어려우므로 www.naver.com과같은문자열로구성된도메인이름으로바꿔사용한다. 사용자가문자열로구성된도메인이름을사용하면 DNS(Domain Name Server) 에의해숫자로구성된 IP 주소로자동변환되게된다. 현재는 4개의숫자로표현된 IP 주소를표현하기위해 32비트의 IP 버전 4(IPv4) 가사용되고있다. 그러나엄청난네트워크장치의증가로각장치에고유하게부여할수있는 IP 주소가고갈됨에따라 128비트의 IP 버전 6(IPv6) 이점점널리사용되는추세이다. 자신의 IP 주소는간단히 localhost라는이름으로사용해도된다. localhost의 IP 주소는 127.0.0.1로지정되어있다. 도메인이름 localhost 내컴퓨터의 IP 주소확인하기윈도우 PC에서명령창을열어 ipconfig 명령을수행하면 [ 그림 16-2] 와같이컴퓨터에할당된 IP 주소를확인할수있다. ipconfig [ 그림 16-2] 내컴퓨터 IP 주소확인 포트 IP는네트워크상의컴퓨터또는시스템을식별한다. 한컴퓨터내에서는여러응용프로그램이네트워크를사용하고있기때문에, IP 주소만가지고는통신하는응용프로그램을식별할수없다. 이경우한컴퓨터내의각응용프로그램은통신을위해가상
788 JAVA 자바프로그래밍 JAVA PROGRAMMING 의연결단인포트 (port) 를생성하고이포트번호로자신을식 별하게한다. 즉, IP 주소는아파트의동번호와같다고볼수 있으며, 포트번호는같은아파트동에있는호번호와같다고 볼수있다. 다른예로 IP 주소는은행지점의주소라할수있 으며, 포트번호는은행내의고객창구번호와같다고할수 있다. 따라서통신을수행하는모든응용프로그램은포트를 이용하여상대방프로그램과데이터를교환한다. 물론상대방 응용프로그램은자신의 IP 주소와포트번호를사전에알고 있어야한다. 응용프로그램과포트사용사례는 [ 그림 16-3] 과같다. 포트 컴퓨터 2 포트 포트 컴퓨터 1 응용프로그램 1 1 1 응용프로그램 1 응용프로그램 2 2 인터넷 2 응용프로그램 2 응용프로그램 3 3 3 응용프로그램 3 [ 그림 16-3] 응용프로그램이자신의포트를이용한통신 잘알려진포트 포트번호는응용프로그램개발자가임의로선택하여사용할수있으나, 기존응용프로그램에서이미사용하고있는포트번호나시스템의포트번호는피하는것이좋다. 시스템혹은기존에잘알려진응용프로그램에서사용하는포트번호를잘알려진포트 (well-known ports) 라고한다. 주로 0~1023 사이의번호를가지므로이범위의포트번호는피하도록한다. 예를들어, Telnet은 23번포트, HTTP는 80번포트, FTP는 21번포트를사용하므로사용자가작성하는응용프로그램에서는이러한포트번호는피해서선택해야한다. CHECK TIME TCP 상에서동작하는응용프로그램을나열하라. IP 주소와포트에대해설명하라. 하나의응용프로그램은반드시하나의포트만사용하여야하는가? 현재자신의컴퓨터의 IP 주소가얼마인지확인하라.
제 16 장네트워크 789 16CHAPTER 16.2 URL 을이용한웹프로그래밍 URL 이란? 컴퓨터로가장흔히하는일이웹서핑 (web surfing) 인데우리가사용하고있는웹브라우저의주소창에입력하는서핑주소가바로 URL이다. [ 그림 16-4] 는네이버의 URL 이다. URL은 Uniform Resource Locator의약자로서인터넷상의자원 ( 리소스 ) 에대한주소를의미한다. 웹브라우저에직접 URL을입력할수도있고웹페이지의링크를클릭하면웹브라우저가해당 URL을브라우저에로드하여보여주기도한다. URL URL [ 그림 16-4] 웹브라우저주소창의 URL URL 구조 URL은 [ 그림 16-5] 와같이프로토콜식별자와자원이름으로구성되어있다. 프로토콜식별자와자원이름은콜론 (:) 으로구분되며자원이름은이중슬래시 (//) 로시작한다. 프로토콜식별자자원이름
790 JAVA 자바프로그래밍 JAVA PROGRAMMING http : //www.naver.com/ 프로토콜 식별자 (protocol identifier) 자원 이름 (resource name) [ 그림 16-5] URL 구조 프로토콜식별자 프로토콜식별자프로토콜식별자는인터넷상의자원을가져올때사용되는통신프로토콜이름이다. 우리가흔히웹이라고부르는것은 HTTP(HyperText Transfer Protocol) 라는프로토콜을사용하는데, 모든홈페이지주소에 http가들어있는것은이때문이다. 이외에도 FTP(File Transfer Protocol), TELNET(TELecommunication NETwork) 등과같은프로토콜이프로토콜식별자로사용될수있다. 실제대부분의브라우저들은 HTTP 외다른프로토콜도지원하는데, [ 그림 16-6] 은브라우저에서 FTP 프로토콜을이용하여 FTP 서버에접속한예이다. [ 그림 16-6] 브라우저에서 FTP 프로토콜을이용하여서버에접속
제 16 장네트워크 791 16CHAPTER 자원이름자원이름은사용되는프로토콜에따라서그구성이달라진다. HTTP를예로들면자원이름은 [ 그림 16-7] 과같이호스트이름, 파일이름, 포트번호등으로구성되나, 대부분의웹사이트의홈페이지는호스트주소만으로자원이름이구성된다. 자원이름 http : //www.myhome.net /index.html :8080 호스트 이름파일 이름포트 번호 [ 그림 16-7] HTTP 의자원이름 자바의 URL 클래스 자바의 API 중에서 java.net 패키지에포함된 URL 클래스는웹상의자원을지정하는 URL정보를나타낸다. 생성자 URL 클래스의주요생성자는다음과같다. URL(String spec) 문자열 spec이지정하는자원에대한 URL 객체생성 URL(String protocol, String host, int port, String file) 프로토콜식별자 protocol, 호스트주소 host, 포트번호 port, 파일이름 file이지정하는자원에대한 URL 객체생성 메소드 URL 클래스의주요메소드는 < 표 16-1> 과같다. 메소드 Object getcontent() 이 URL 의컨텐트를리턴 설명 < 표 16-1> URL 클래스의주요메소드 String getfile() 이 URL 의파일이름리턴 String gethost() 이 URL 의호스트이름리턴 String getpath() 이 URL 의경로부분리턴 int getport() 이 URL 의포트번호리턴
792 JAVA 자바프로그래밍 JAVA PROGRAMMING String getprotocol() 이 URL 의프로토콜이름리턴 InputStream openstream() URL 주소와연결한뒤이연결로부터입력받을수있는 InputStream 객체리턴 URLConnection openconnection() URL 주소의원격객체에접속한뒤통신할수있는 URLConnection 객체리턴 URL 클래스를이용하여연결된상대편으로부터데이터를읽을때는그전에먼저 openstream() 메소드를이용하여입력스트림을연다. 그러고나면일반적인입력스트림에서읽듯이데이터를읽어온다. URL 객체생성 절대경로상대경로 상대편과통신하기위해서는사전에상대편의주소를가진 URL 객체를생성하여야한다. URL 객체는 URL의주소와 URL 클래스의생성자를이용하여생성한다. URL 객체를생성하는방법에는상대편에대한절대경로를이용하는방법과상대경로를이용하는방법이있다. 다음은절대경로로 URL 객체를생성하는방법이다. URL homepage = new URL("http://news.hankooki.com"); 다음은이미생성된 URL 객체를이용하여이 URL에대한상대경로로새로운 URL 객체를생성하는방법이다. URL opinion = new URL(homePage, "opinion/editorial.htm"); opinion 이라는 URL 은결국다음주소를의미한다. "http://news.hankooki.com/opinion/editorial.htm" URL 객체를생성할때잘못된주소의 URL을입력하면 MalformedURLException 예외가발생하므로 try-catch 문으로예외처리를해야한다.
제 16 장네트워크 793 16CHAPTER URL 파싱하기 예제 16-1 URL 클래스를이용하여 URL을구성하는프로토콜이름, 호스트주소, 포트번호등각부분을파싱해보자. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.net.*; public class ParseURL { public static void main(string[] args) { URL opinion = null; URL homepage = null; try { homepage = new URL( http://news.hankooki.com:80 ); // 절대경로로 URL 객체생성 opinion = new URL(homePage, opinion/editorial.htm ); // 상대경로로 URL 객체생성 catch (MalformedURLException e) { System.out.println( 잘못된 URL입니다. ); System.out.println( protocol = + opinion.getprotocol()); // 프로토콜출력 System.out.println( host = + opinion.gethost()); // 호스트이름출력 System.out.println( port = + opinion.getport()); // 포트번호출력 System.out.println( path = + opinion.getpath()); // 경로부분출력 System.out.println( filename = + opinion.getfile()); // 파일이름출력 실행 결과 protocol = http host = news.hankooki.com port = 80 path = /opinion/editorial.htm filename = /opinion/editorial.htm URL 객체를이용하여상대편으로부터데이터읽기 URL 객체를생성한것만으로원격지와연결되지는않는다. 원격지와연결하고원격지로부터데이터를가져오기위해서는 URL의 openstream() 메소드를이용하여야한다. 그리고 openstream() 이리턴하는 InputStream 객체를이용하여스트림입력을수행해야한다. openstream()
794 JAVA 자바프로그래밍 JAVA PROGRAMMING 예제 16-2 URL 주소에서데이터읽기 http 프로토콜로 www.nate.com 사이트에접속한뒤 www.nate.com에서보내주는웹페이지를받아보자. 웹페이지는모두텍스트데이터이다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.net.*; import java.io.*; public class URLRead { public static void main(string[] args) { try { URL aurl = new URL( http://www.nate.com ); // URL 객체생성 BufferedReader in = new BufferedReader(new InputStreamReader(aURL. openstream())); // URL 객체에서입력스트림생성 String inputline; while ((inputline = in.readline())!= null) // 한행씩읽음 System.out.println(inputLine); in.close(); catch (IOException e) { System.out.println( URL에서데이터를읽는중오류가발생했습니다. ); URLRead 자바 프로그램을실행하면 www.nate.com 에서보내주는 html 문서를출력한다.
제 16 장네트워크 795 16CHAPTER URLConnection 클래스 URLConnection 클래스는주어진원격지의주소 URL에네트워크접속후데이터를보내거나받을수있도록한다. 앞서설명한 URL 클래스와기능이비슷하지만보다효과적이다. URLConnection 객체를생성하는방법은다음두가지이다. URLConnection 클래스 URL.openConnection() 을이용하는방법 URLConnection 생성자를이용하는방법 URL.openConnection() 이용우선첫번째방법은다음과같이사용할수있다. URL aurl = new URL("http://www.naver.com"); URLConnection uc = aurl.openconnection(); // 원격지와연결한다. uc는네이버사이트에연결된 URLConnection 객체이며이객체를사용하여네이버사이트의정보를전송하거나받을수있다. URLConnection 생성자이용두번째방법은다음과같이생성자를이용하여 URLConnection 객체를만들고 connect() 메소드를이용하여원격지와연결하는방법이다. URL aurl = new URL("http://www.naver.com"); URLConnection uc = new URLConnection(aURL); uc.connect(); // 원격지와연결한다. 이방법은연결하기전에여러가지인자들과요청과관련된속성들을설정할수있다. 실제 URL에대한연결은 URLConnection 객체의 connect() 메소드를호출하여자바프로그램과 URL의네트워크상연결을설정하는것이다. 메소드 URLConnection 클래스의주요메소드는 < 표 16-2> 와같다. 메소드 abstract void connect() Object getcontent() String getcontentencoding() 설명 URL에의해참조되는외부리소스와통신연결설정 URL 연결에서컨텐트를가져옴컨텐트인코딩필드를리턴 < 표 16-2> URLConnection 클래스의주요메소드
796 JAVA 자바프로그래밍 JAVA PROGRAMMING int getcontentlength() String getcontenttype() boolean getdoinput() boolean getdooutput() InputStream getinputstream() OutputStream getoutputstream() URL geturl() void setdoinput(boolean doinput) void setdooutput(boolean dooutput) 컨텐트길이필드리턴컨텐트타입필드리턴 URLConnection 객체의 doinput 필드값리턴 URLConnection 객체의 dooutput 필드값리턴설정된연결에서데이터를읽을입력스트림리턴설정된연결로데이터를출력할출력스트림리턴 URLConnection 객체의 URL 필드값리턴 URLConnection 객체의 doinput 필드값설정 URLConnection 객체의 dooutput 필드값설정 URLConnection 클래스에는 doinput과 dooutput 필드가있는데모두 boolean 타입이다. doinput이 true로설정되면 URLConnection 객체로표현되는 URL 연결이입력을위해사용됨을의미하며, dooutput이 true로설정되면출력을위해사용됨을의미한다. URL 객체와달리 URLConnection 객체는데이터를보낼수도있는것에유의하자. URLConnection 객체를이용하여원격지데이터받기 URLConnection 객체를이용하여데이터를가져오는방법은 URL 객체와매우유사하 다. URLConnection 객체에서 getinputstream() 메소드를이용하여입력스트림을얻은후에스트림입력을수행하면된다. 예제 16-3 URLConnection 으로원격지데이터읽기 URLConnection 객체를이용하여 www.daum.net에연결하여데이터를읽고화면에출력하는프로그램을작성하라. 1 2 3 4 5 6 7 8 9 10 import java.io.*; import java.net.*; public class URLConnectionReader { public static void main(string[] args) { try { URL aurl = new URL( http://www.daum.net ); // URL 객체생성 URLConnection uc = aurl.openconnection(); // URL 객체에서 URLConnection 객체생성 BufferedReader in = new BufferedReader(new InputStreamReader(uc. getinputstream())); // 입력스트림생성 String inputline;
제 16 장네트워크 797 16CHAPTER 11 12 13 14 15 16 17 18 19 while ((inputline = in.readline())!= null) // 한행씩읽음 System.out.println(inputLine); in.close(); catch (IOException e) { System.out.println( URL에서데이터를읽는중오류가발생했습니다. ); URLConnection 객체를이용하여원격지로데이터보내기 앞절에서와같이 URL 객체나 URLConnection 객체를이용하여웹서버에서데이터를읽어오는방법을 HTTP GET이라고하는데, 웹브라우저에서의동작의대부분은 HTTP GET이라할수있다. 이에반해웹서버에데이터처리를요청할때처리될데이터를같이보낼수있는데이방법을 HTTP POST라고한다. HTTP POST를이용하면서버에폼 (form) 데이터나파일을업로드할수도있으며, 함께보내진데이터를서버가처리한후다시클라이언트에응답을보내게된다. 서버에서데이터를읽어오는것은 HTTP GET과다르지않다. URLConnection 객체는 URL 객체와달리 HTTP POST 방식으로서버에데이터를전송할수있으며, 이것이 URL과 URLConnection의가장큰차이이다. HTTP POST에대한이해를돕기위해 [ 그림 16-8] 을보자. HTTP GET HTTP POST
798 JAVA 자바프로그래밍 JAVA PROGRAMMING [ 그림 16-8] 폼이포함된웹페이지 이그림은성 (last name) 과이름 (first name) 을입력하는필드가있는 HTML 폼 (form) 이다. 이두필드에데이터를입력한후 send 버튼을누르면웹서버로요청과함께필드에입력한데이터를전송하는데, 이것이 HTTP POST이다. 가장흔하게볼수있는폼이포함된웹페이지는회원가입페이지나실명확인페이지와같이여러필드에데이터를입력하는페이지이다. 웹서버는전송받은데이터를처리하며, 이에따른웹페이지를구성하여요청한클라이언트에응답을보낸다. URLConnection 객체가데이터를쓴다는것은바로 HTTP POST 방식으로웹서버에요청과함께데이터를보내는것을의미한다. 서버에데이터를보내기위해서는다음과같은단계가필요하다. 1. URL 생성 2. URL 객체에서 URLConnection 객체얻기 3. setdooutput() 메소드로 dooutput 필드를 true로설정 4. connect() 메소드로연결설정 5. 연결에서출력스트림얻기 6. 출력스트림에데이터출력 7. 출력스트림닫기
제 16 장네트워크 799 16CHAPTER URLConnection 을이용하여웹서버에데이터보내기 예제 16-4 URLConnection 객체를이용하여웹서버에데이터를보내고웹서버로부터응답데이터를받아화면에출력하는응용프로그램을작성하라. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.io.*; import java.net.*; public class URLConnectionWriter { public static void main(string[] args) { try { URL aurl = new URL( http://httpbin.org/post ); // POST가가능한사이트 URL 객체생성 URLConnection uc = aurl.openconnection(); // URLConnection 객체생성 uc.setdooutput(true); // 출력모드설정 OutputStreamWriter out = new OutputStreamWriter(uc.getOutputStream()); // 출력스트림생성 out.write( Firstname=Kitae&Lastname=Hwang ); // 서버에데이터보내기 out.close(); BufferedReader in = new BufferedReader(new InputStreamReader(uc. getinputstream())); // 서버에서응답을읽기위한입력스트림생성 String inputline; while ((inputline = in.readline())!= null) // 한행씩읽음 System.out.println(inputLine); in.close(); catch (IOException e) { System.out.println( URL에데이터를입출력중에오류가발생했습니다. ); 서버에 보내는 인자는 '&' 로 구분한다. 웹 서버에 post 데이터를 보낸 후웹 서버로부터 받은 응답 데이터. 이 데이터는 html 문서이다.
800 JAVA 자바프로그래밍 JAVA PROGRAMMING CHECK TIME http://docs.oracle.com/javase/7/docs/api/ 를나타내는 URL 객체를생성하라. 1 번에서생성한 URL 객체에서 URLConnection 객체를획득하는코드를작성하라. 2 번에서생성한 URLConnection 객체에서입력스트림을얻어와서해당 URL 의내용을콘솔에출력하는코드를작성하라. 16.3 소켓프로그래밍 소켓 소켓 Socket 앞절의URL이나 URLConnection 객체를이용한웹프로그래밍에서서버와통신할때는간단히입출력스트림을생성하여데이터를주고받았다. 연결이어떻게설정되는지, 어떤포트를사용하는지, 서버와클라이언트가어떤순서로통신하는지등자세히신경쓸필요가없었다. 그러나개발자가서버와클라이언트사이의통신을보다자세히제어하거나 TCP 프로토콜상에서동작하는새로운응용프로토콜을만들어통신을하기원하는경우에는직접소켓을이용하여프로그래밍을해야한다. 자바에서소켓을이용하여데이터통신을하려면소켓 (Socket) 클래스를이용한다. 소켓은네트워크상에서통신하는두응용프로그램간의양방향통신링크의한쪽끝을의미한다. [ 그림 16-9] 와같이소켓은특정포트번호에연결되어있어데이터를보내거나받을때해당응용프로그램을식별할수있다. 웹 브라우저 소켓 포트 인터넷 포트 소켓 웹 서버 [ 그림 16-9] 소켓이용
제 16 장네트워크 801 16CHAPTER 보통정보를제공하는쪽을서버라고부르며, 이정보를이용하는쪽을클라이언트라고부른다. 통신은클라이언트에서먼저서버에접속하여서비스를요청하는방식으로이루어지고, 서버는데이터나서비스를제공하는방식으로이루어진다. 자바소켓에는서버소켓과클라이언트소켓이있다. 클라이언트소켓은클라이언트를위한것이며, 서버소켓은서버응용프로그램을위한것이다. 서버클라이언트클라이언트소켓서버소켓 소켓을이용한서버클라이언트통신프로그램의구조이절에서는서버클라이언트의통신구조를전체적으로묘사하고자하며, 구체적인내용은다음절에서설명한다. 소켓을이용하여통신하는서버클라이언트의전형적인구조는 [ 그림 16-10] 과같다. 클라이언트응용프로그램은 Socket 클래스를이용하여소켓객체를생성하고서버와통신하며, 서버응용프로그램은 ServerSocket 클래스를이용하여소켓객체를생성하고클라이언트와통신한다. 서버는클라이언트의접속을받기위해서버포트에대한요청을기다린다. 이때클라이언트에서서버 IP의주소와서버가기다리는포트번호를가지고서버에접속한다. 서버는 accept() 메소드에서클라이언트와통신하는전용소켓을하나따로생성하여접속된클라이언트와통신한다. 서버는서버소켓을클라이언트와통신하는목적으로사용하지않고클라이언트로부터의접속을받는목적으로만사용한다. 서버는클라이언트가접속할 때마다 accept() 메소드에서따로전송소켓을생성하여클라이언트와통신하도록한다. 통신이끝나면소켓을닫는다. ServerSocket Socket clientsocket = new Socket( 서버 IP, 서버 port); 접속 listener = new ServerSocket( 서버 port); Socket socket = listener.accept(); Socket clientsocket.getoutputstream(); socket.getinputstream(); clientsocket 을 이용하여 데이터 입출력 socket 을 이용하여 데이터 입출력 clientsocket.close(); socket.close(); 클라이언트 서버 [ 그림 16-10] 소켓을이용한서버클라이언트통신프로그램의전형적인구조
802 JAVA 자바프로그래밍 JAVA PROGRAMMING Socket 클래스, 클라이언트소켓 Socket Socket은 java.net 패키지에포함되어있는클래스로서클라이언트소켓을구현한다. 즉, 서버와통신하기위해클라이언트응용프로그램에서사용하는소켓이다. Socket 의생성자와메소드는각각 < 표 16-3>, < 표 16-4> 와같다. Socket 클래스의생성자는연결할서버의 IP 주소 ( 또는도메인주소 ) 와포트번호를인자로받아서새로운 Socket 객체를생성한다. 클라이언트자신의주소와포트번호가아님에주의하자. 이제 Socket 클래스를이용하여클라이언트응용프로그램을작성하는방법을자세히살펴보자. 클라이언트소켓생성및서버접속상대편서버의 IP 주소가 128.12.1.1이고상대편포트번호가 5550이면다음과같이클라이언트소켓객체를생성한다. Socket clientsocket = new Socket("128.12.1.1", 5550); Socket 객체가생성되면곧바로 128.12.1.1 의주소로자동접속이이루어진다. 네트워크입출력스트림생성소켓이만들어지고서버와연결이된후에는 Socket 클래스의 getinputstream() 과 getoutputstream() 메소드를이용하여서버와설정된네트워크연결을다음과같이데이터스트림으로만든다. BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())); in, out 객체를이용하여일반스트림을입출력하는방식과동일하게네트워크데이터를입출력한다. 서버로데이터전송이제앞서만들어진스트림 out을통해데이터를전송한다. 다음은 hello 문자열을서버로전송하는코드이다. out.write("hello"+"\n"); out.flush();
제 16 장네트워크 803 16CHAPTER out.flush() 를호출하면스트림속의데이터를남기지않고즉각모두전송한다. 서버로부터데이터수신앞서만들어진스트림 in을통해서버로부터데이터를수신할수있다. 다음은각각서버로부터한개의문자를입력받는코드와한행의문자열을입력받는코드이다. int x = in.read(); // 서버로부터한개의문자수신 String line = in.readline(); // 서버로부터한행의문자열수신 네트워크접속종료데이터송수신을모두수행하고네트워크의접속을종료하고자하면다음과같이한다. clientsocket.close(); 생성자 Socket(InetAddress address, int port) Socket(String host, int port) 설명소켓을생성하여지정된 IP 주소 (address) 와포트번호 (port) 에연결한다. 소켓을생성하여지정된호스트 (host) 와포트번호 (port) 에연결한다. 호스트이름이 null인경우는루프백 (loopback) 주소로가정한다. < 표 16-3> Socket 클래스의주요생성자 메소드 void close() 소켓을닫는다. 설명 < 표 16-4> Socket 클래스의주요메소드 void connect(socketaddress endpoint) InetAddress getinetaddress() InputStream getinputstream() InetAddress getlocaladdress() int getlocalport() int getport() OutputStream getoutputstream() boolean isbound() boolean isconnected() boolean isclosed() void setsotimeout(int timeout) 서버에연결연결한서버의주소리턴소켓에대한입력스트림리턴소켓이연결된로컬주소리턴소켓이연결된로컬포트번호리턴소켓이연결한서버의포트번호리턴소켓에대한출력스트림리턴소켓이로컬주소에연결되어있으면 true 리턴소켓이서버에연결되어있으면 true 리턴소켓이닫혀있으면 true 리턴데이터읽기타임아웃시간지정. 0이면타임아웃해제
804 JAVA 자바프로그래밍 JAVA PROGRAMMING ServerSocket 클래스, 서버소켓 ServerSocket 클래스 ServerSocket 클래스는서버소켓을구현한다. ServerSocket 클래스는 java.net 패키지에포함되어있으며 ServerSocket 클래스의생성자와메소드는각각 < 표 16-5>, < 표 16-6> 과같다. ServerSocket은클라이언트측으로부터연결요청을기다리는모니터링을위해사용되며서버가클라이언트의연결요청을수락하면 Socket 객체를새로생성한다. 이 Socket 객체를이용하여클라이언트와통신하게되므로, ServerSocket은일반적인데이터의송수신에는사용되지않는다. 서버소켓생성 ServerSocket 클래스의생성자는사용할포트번호를인자로받아서새로운 ServerSocket 객체를생성한다. 이포트번호는현재자신의포트번호이다. 이미사용중인포트번호를지정하면오류가발생한다. 5550번포트를사용하는서버소켓을생성하는예를들면다음과같다. ServerSocket serversocket = new ServerSocket(5550); 클라이언트로부터접속기다림 ServerSocket 클래스의 accept() 메소드를이용하여클라이언트로부터의연결요청을기다린다. accept() 메소드는연결요청이오면다음과같이새로운 Socket 객체를리턴한다. Socket socket = serversocket.accept(); 서버에서클라이언트와의데이터통신은새로만들어진 Socket 객체를통해서이루어진다. 그러므로 ServerSocket 클래스는 Socket 클래스와달리주어진연결에대해입출력스트림을만들어주는메소드가없다. 네트워크입출력스트림생성 accept() 메소드에서얻은 Socket 객체의 getinputstream() 과 getoutputstream() 메소드를이용하여클라이언트와설정된네트워크연결을다음과같이데이터스트림으로만든다. BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
제 16 장네트워크 805 16CHAPTER in, out 객체를이용하여일반스트림을입출력하는방식과동일하게네트워크데이터를입출력한다. 클라이언트로부터데이터수신앞서만들어진스트림 in을이용하여클라이언트로부터데이터를수신할수있다. 다음은각각클라이언트로부터한개의문자를입력받는코드와한행의문자열을입력받는코드이다. int x = in.read(); // 클라이언트로부터한개의문자수신 String line = in.readline(); // 클라이언트로부터한행의문자열수신 클라이언트로데이터전송앞서만들어진스트림 out을통해클라이언트로데이터를전송할수있다. 다음은 Hi!, Client 문자열을클라이언트로전송하는코드이다. out.write("hi!, Client"+"\n"); out.flush(); out.flush() 를호출하면스트림속의데이터를남기지않고즉각모두클라이언트로전송한다. 네트워크접속종료데이터송수신을모두수행하고네트워크의접속을종료하고자하면다음과같이한다. socket.close(); 서버응용프로그램종료더이상클라이언트의접속을받지않고서버응용프로그램을종료하고자하는경우다음과같이 ServerSocket을종료시킨다. serversocket.close(); 생성자 ServerSocket(int port) 지정된포트번호 (port) 와결합된소켓을생성한다. 설명 < 표 16-5> ServerSocket 클래스의주요생성자
806 JAVA 자바프로그래밍 JAVA PROGRAMMING < 표 16-6> ServerSocket 클래스의주요메소드 메소드 설명 Socket accept() 연결요청을기다리다요청이들어오면수락하고 Socket 객체리턴 void close() 서버소켓을닫는다. InetAddress getinetaddress() int getlocalport() boolean isbound() boolean isclosed() void setsotimeout(int timeout) 서버소켓에연결된로컬주소리턴서버소켓이연결요청을모니터링하는포트번호리턴서버소켓이로컬주소에연결되어있으면 true 리턴서버소켓이닫혀있으면 true 리턴 accept() 에대한타임아웃시간지정. 0이면타임아웃해제 잠깐! 통신프로그램을작성하기위해서는운영체제가지원하는 TCP/IP 라이브러리를굳이사용할필요가없다. 소켓의등장으로인해통신프로그램개발자는매우편리해졌다. 소켓은자바뿐만아니라거의모든언어에라이브러리로지원되는공통적인개념이므로자바의소켓을알면다른언어의소켓라이브러리역시이해하기쉽다. 독자들이통신프로그램을작성한다고하면일단무조건소켓을생각하고여기서부터시작하면된다. 16.4 서버 - 클라이언트채팅예제 예제개요서버와클라이언트가번갈아채팅문자를보내는간단한채팅프로그램예제를통해자바에서소켓을이용하여어떻게클라이언트와서버간에데이터를주고받는지실습해보기로한다. 본예제에서사용할채팅프로그램은다음과같다. 서버와클라이언트가 1:1로채팅 서버와클라이언트간의메시지구분을위해서버는메시지앞에 서버 > 를접두어로붙여메시지를전송하며, 클라이언트는 클라이언트 > 를접두어로붙여메시지를전송 서버와클라이언트가번갈아가면서메시지전송및수신 클라이언트가 bye를보내면프로그램종료
제 16 장네트워크 807 16CHAPTER 클라이언트 > 안녕? 너도 안녕 서버 화면 연결 요청 새로운 소켓으로 연결 안녕? 서버 > 너도 안녕 bye 클라이언트 화면 클라이언트사용자가먼저 " 클라이언트 > 안녕?" 을보내자서버에서 " 서버 > 너도안녕?" 을보낸경우입니다. 클라이언트에서 "bye" 를보내서버와의연결을 서버 " 클라이언트 > 안녕?" 클라이언트 종료하였습니다. " 서버 > 너도 안녕?" "bye" [ 그림 16-11] 채팅예제실행흐름 ( 초록색글자는사용자의키입력임 ) 서버프로그램 다음절의채팅프로그램의전체소스를보기전에이절에서는단계별로서버프로그램작성에필요한내용을소스와함께설명한다. 서버소켓생성서버용자바응용프로그램에서는시스템에서사용되지않은포트번호 9999로서버소켓을생성한다. 서버소켓은다음코드와같이생성한다. ServerSocket listener = new ServerSocket(9999); 클라이언트요청대기서버소켓을생성한후생성된서버소켓으로연결요청이오는지모니터링하면서대기하는코드는다음과같다. Socket socket = listener.accept(); accept() 메소드는연결요청이오면수락과함께새로운 Socket 객체를생성하여새소켓으로클라이언트와통신하도록한다. 새로운소켓의포트번호는 9999가아니며자동으로할당된다. 클라이언트와통신을위한입출력스트림생성클라이언트와의데이터송수신은스트림을생성하여데이터를송수신한다. 데이터의종류에따라바이트스트림또는문자스트림을생성하여사용하면된다. 본예제의
808 JAVA 자바프로그래밍 JAVA PROGRAMMING 채팅과같이문자열을송수신하는경우는문자스트림을사용하며, 파일을전송하는경우는바이트스트림을사용한다. 본예제에서는효율적입출력을위하여버퍼스트림을사용한다. 설정된연결에서스트림을생성하는코드는다음과같다. BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 클라이언트로부터데이터수신 in 스트림생성이후부터는일반입력스트림에서데이터를입력받는방법과동일하다. 다음코드는입력스트림 in에서한행의데이터를수신하는코드이다. String inputmessage = in.readline(); 클라이언트에서한행의문자열을보내올때까지서버는어떤동작도하지않고기다린다. 클라이언트로데이터송신서버에서클라이언트로데이터를보내는방법은일반출력스트림에서데이터를출력하는방법과동일하다. 아래의코드는콘솔에서사용자로부터문자열을입력받아클라이언트로송신하는코드이다. BufferedReader stin = new BufferedReader(new InputStreamReader(System.in)); String outputmessage = stin.readline(); // 콘솔에서읽는다. out.write(" 서버 >" + outputmessage+" \n"); // 클라이언트로전송한다. out.flush(); flush() 메소드는스트림 out 에남아있는모든데이터를클라이언트로송신한다. 연결종료모든데이터의송수신이끝나서더이상의클라이언트와서버의연결이필요하지않은경우에는소켓을닫는다. 소켓을닫으면소켓의입출력스트림도같이닫힌다. 서버소켓을닫아버리면더이상의클라이언트연결요청을받을수없다는것에유의한다. 다음의코드는소켓과서버소켓을닫는코드이다.
제 16 장네트워크 809 16CHAPTER socket.close(); // 통신소켓을닫는다. listener.close(); // 서버소켓을닫는다. 소켓또는서버소켓을닫으면여기에관련된모든자원이해제된다. 클라이언트프로그램 이절에서는단계별로클라이언트프로그램작성에필요한내용을소스와함께설명한다. 연결요청클라이언트의연결요청이있으면연결할서버의호스트주소와서버의포트번호로클라이언트소켓을생성한다. 다음은클라이언트소켓생성코드이다. socket = new Socket("localhost", 9999); 본예제에서는동일한컴퓨터내에서서버와클라이언트가동작하므로호스트이름으로 localhost 로지정하였다. localhost 는현재프로그램이실행되는컴퓨터를의미한다. 만약서버가다른컴퓨터에서동작한다면서버의 IP 주소또는도메인이름을지정하면된다. 서버와통신을위한입출력스트림생성서버와의데이터송수신을위해스트림을생성한다. 클라이언트측에서도송수신되는데이터의종류에따라바이트스트림또는문자스트림을생성하여사용한다. 이예제에서는효율적입출력을위하여버퍼스트림을사용한다. 클라이언트소켓으로부터입출력을위한스트림을생성하는코드는다음과같다. BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 서버에데이터송신스트림생성이후는일반출력스트림에서데이터를출력하는방법과동일하다. 다음코드는콘솔에서입력받은문자열을서버로송신하는코드이다.
810 JAVA 자바프로그래밍 JAVA PROGRAMMING BufferedReader stin = new BufferedReader(new InputStreamReader(System.in)); String outputmessage = stin.readline(); // 콘솔에서읽는다. out.write(" 클라이언트 >"+outputmessage+" \n"); // 서버로전송한다. out.flush(); flush() 메소드는스트림에남아있는모든데이터를서버로송신한다. 서버로부터데이터수신스트림생성이후는일반입력스트림에서데이터를입력받는방법과동일하다. 다음의코드는서버에서한행의문자열을보내올때까지어떤동작도하지않고기다리는것을나타낸다. String inputmessage = in.readline(); 연결종료모든데이터의송수신이끝나서더이상의서버와연결이필요하지않은경우에는소켓을닫는다. 소켓을닫으면소켓의입출력스트림도같이닫힌다. 다음의코드는소켓을닫는코드이다. socket.close(); 소켓을닫으면여기에관련된모든자원이해제된다. 클라이언트서버채팅소스코드 예제전체소스코드는다음과같다. 서버프로그램 ServerEx.java 1 2 3 4 5 6 7 import java.io.*; import java.net.*; public class ServerEx { public static void main(string[] args) { BufferedReader in = null; BufferedReader stin = null;
제 16 장네트워크 811 16CHAPTER 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 BufferedWriter out = null; ServerSocket listener = null; Socket socket = null; try { listener = new ServerSocket(9999); // 서버소켓생성 socket = listener.accept(); // 클라이언트로부터연결요청대기 System.out.println(" 연결됨 "); in = new BufferedReader(new InputStreamReader(socket. getinputstream())); // 클라이언트로부터의입력스트림 stin = new BufferedReader(new InputStreamReader(System.in)); // 키보드로부터의입력스트림 out = new BufferedWriter(new OutputStreamWriter(socket. getoutputstream())); // 클라이언트로의출력스트림 String inputmessage; while (true) { inputmessage = in.readline(); // 클라이언트에서한행의문자열읽음 if (inputmessage.equalsignorecase("bye")) // 클라이언트가 "bye" 를보내면연결종료 break; System.out.println(inputMessage); // 클라이언트가보낸메시지화면에출력 String outputmessage = stin.readline(); // 키보드에서한행의문자열읽음 out.write(" 서버 >" + outputmessage+"\n"); // 키보드에서읽은문자열전송 out.flush(); catch (IOException e) { System.out.println(e.getMessage()); finally { try { socket.close(); // 클라이언트와통신용소켓닫기 listener.close(); // 서버소켓닫기 catch (IOException e) { System.out.println(" 클라이언트와채팅중오류가발생했습니다.");
812 JAVA 자바프로그래밍 JAVA PROGRAMMING 클라이언트프로그램 ClientEx.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import java.io.*; import java.net.*; public class ClientEx { public static void main(string[] args) { BufferedReader in = null; BufferedReader stin = null; BufferedWriter out = null; Socket socket = null; try { socket = new Socket("localhost", 9999); // 클라이언트소켓생성 in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 서버로부터의입력스트림 stin = new BufferedReader(new InputStreamReader(System.in)); // 키보드로부터의입력스트림 out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 서버로의출력스트림 String outputmessage; while (true) { outputmessage = stin.readline(); // 키보드에서한행의문자열읽음 if (outputmessage.equalsignorecase("bye")) { // "bye" 가입력되면메시지전송후연결종료 out.write(outputmessage); out.flush(); break; out.write(" 클라이언트 >"+outputmessage+"\n"); // 키보드에서읽은문자열전송 out.flush(); String inputmessage = in.readline(); // 서버에서한행의문자열읽음 System.out.println(inputMessage); // 서버가보낸메시지화면에출력 catch (IOException e) { System.out.println(e.getMessage()); finally { try { socket.close(); // 클라이언트소켓닫기 catch (IOException e) { System.out.println(" 서버와채팅중오류가발생했습니다.");
제 16 장네트워크 813 16CHAPTER 서버 - 클라이언트채팅예제실행 이제만든예제를실행해보자. 예제를실행하기위해서는서버와클라이언트를위해각각명령창을하나씩생성한다. 다음과같은순서로진행한다. 1. 명령창을하나열고서버프로그램을먼저실행시켜클라이언트의연결요청을기다린다. [ 그림 16-12] 와같다. 서버 [ 그림 16-12] 서버가먼저실행되어클라이언트로부터연결을기다리고있는서버명령창 2. 서버프로그램을실행한후에 [ 그림 16-13] 과같이다시다른명령창을열어클라이언트프로그램을실행하고서버와연결을설정한다. 연결이설정되면 [ 그림 16-14] 와같이서버의명령창에는 연결됨 이출력된다. 클라이언트 [ 그림 16-13] 클라이언트프로그램을실행한클라이언트명령창
814 JAVA 자바프로그래밍 JAVA PROGRAMMING 서버 [ 그림 16-14] 클라이언트와접속된서버명령창 3. 채팅은클라이언트에서먼저시작하여순서대로메시지를번갈아주고받는다. [ 그림 16-15], [ 그림 16-16] 은각각클라이언트와서버의실행화면이다. 클라이언트사용자가 안녕? 을콘솔에입력하면 클라이언트 > 안녕? 을서버로전송하고서버에서는받은문자열을그대로출력한다. 그리고 [ 그림 16-15] 와같이서버에서사용자로부터입력받은 너도안녕? 문자열에 서버 > 를덧붙여클라이언트로전송한다. 서버 [ 그림 16-15] 클라이언트로부터 클라이언트 > 안녕? 을받아출력하고사용자로부터메시지를입력받아전송하는서버명령창 클라이언트 [ 그림 6-16] 서버로부터 서버 > 너도안녕? 메시지를전송받아출력하는클라이언트명령창
제 16 장네트워크 815 16CHAPTER 4. 클라이언트에서 bye 를입력하여채팅종료채팅을종료하기위해서는클라이언트에서 bye 를서버에게전송하면된다. 사용자가 bye 를입력하면이문자열을그대로서버에게보내채팅을종료한다. [ 그림 16-17] 은 bye 문자열을입력받아서버로보내는과정이다. [ 그림 16-18] 은클라이언트로부터 bye 문자열을받고종료한서버의화면이다. 클라이언트 [ 그림 16-17] 클라이언트가사용자로부터 bye 를입력받고서버로전송. 클라이언트종료 서버 [ 그림 16-18] 클라이언트로부터 bye 를전송받아서버프로그램종료 서버소켓에스트림을생성하는메소드가없는이유를설명하라. 연결이설정된클라이언트소켓에서바이트입출력스트림을생성하는코드를작성하라. CHECK TIME
816 JAVA 자바프로그래밍 JAVA PROGRAMMING SUMMARY 요약 TCP 프로토콜은다른두시스템간에신뢰성있는데이터의전송을관장하는프로토콜이며, IP는패킷교환네트워크에서송신호스트와수신호스트가데이터를주고받는것을관장하는프로토콜이다. IP 주소는네트워크상에서유일하게식별될수있는숫자로구성된주소이다. 포트는시스템내부에수행되는여러프로그램간에통신을위한가상의연결단으로서통신할프로그램을식별한다. URL은 Uniform Resource Locator의약자로서인터넷상의리소스에대한주소를의미한다. URL 클래스는웹상의자원을지정하는 URL을나타낸다. URL 객체를이용하여데이터를가져올때는 openstream() 메소드를이용하여일반적인스트림입력을수행한다. URLConnection 객체를이용하여 URL이지정하는외부리소스에데이터를읽고쓸수있다. 소켓은네트워크상에서수행되는두프로그램간의양방향통신링크의한쪽끝을의미하며포트에연결된다. 자바소켓에는서버소켓인 ServerSocket 클래스와클라이언트소켓인 Socket 클래스가있다. 클라이언트소켓인 Socket 객체는연결할서버의 IP 주소또는도메인주소와포트번호를인자로받아서생성한다. 서버소켓인 ServerSocket 객체는연결요청을모니터링할포트번호를인자로받아서생성한다. ServerSocket 객체는연결요청만모니터링하며연결이이루어진후에는 Socket 객체를리턴하여이객체를통해클라이언트와통신한다. 연결이설정된후에는소켓에서스트림을만들고일반스트림입출력과동일하게데이터를입출력한다. 연결을종료할때는소켓의 close() 메소드로소켓을닫는다. 서버소켓을닫으면더이상의연결요청을모니터링하지않는다.
제 16 장네트워크 817 16CHAPTER Open Challenge 스레드를이용한서버 - 클라이언트채팅 본문에서다루었던서버-클라이언트채팅예제를스레드와스윙컴포넌트를이용하여확장해보자. 본문의예제는단일스레드로동작되므로서버와클라이언트가순서대로번갈아가면서메시지를주고받았으나, 스레드를이용하면순서에상관없어자유롭게메시지를서로주고받을수있다. 메시지를입력하는도중상대방메시지가수신되어출력되면전송할메시지와전송된메시지가섞여서알아보기어려우므로 GUI를만들어상대방메시지를출력하는창과상대방에게보낼메시지를입력하는창을분리하도록하고메시지출력창에는자기가입력한메시지와상대방에게서전송받은메시지모두출력되도록한다. 본문예제와달리 "bye" 라는메시지로끝내지않으며어느한쪽이접속을끊으면프로그램이종료되도록한다. 실행예시화면은다음과같다. CharServer.java 를 먼저실행한 후에 ChatClient.java 를실행한다.
818 JAVA 자바프로그래밍 JAVA PROGRAMMING 연습문제 EXERCISE 이론문제 1. 응용프로그램계층의프로토콜이아닌것은? 1 HTTP 2 TELNET 3 FTP 4 UDP 2. 윈도우 PC 의명령창에서내 PC 의 IP 주소를확인하는명령은? 3. 다음 URL에대한설명중틀린것은? 1 URL은 Unified Resource Locator의약자이다. 2 URL은프로토콜식별자와자원이름으로구성된다. 3 인텃넷상의자원에대한주소를나타낸다. 4 프로토콜식별자로는 HTTP만이사용가능하다. 4. URL 객체 myhomepage 는내홈페이지를나타내는 URL 객체라고하자. 내홈페이지밑 의 photo/index.html은내가찍은사진을보여주는페이지라고하면이페이지를나타내는새로운 URL 객체를 myhomepage 객체를이용하여생성하라. 5. 다음은지정된 URL에서데이터를읽어들이는프로그램이다. 아래소스에서빈칸을채워라. import java.io.*; import java.net.*; public class Example { public static void main(string[] args){ URL aurl; try { aurl = new URL("http://www.nate.com"); InputStreamReader in = new InputStreamReader( );
제 16 장네트워크 819 16CHAPTER int c; while ((c = in.read())!= -1) System.out.print((char)c); in.close(); catch (MalformedURLException e) { System.out.println(" 잘못된 URL형식입니다."); catch (IOException e) { System.out.println(" 입출력오류가발생했습니다."); 6. 다음프로그램의출력을나타내라. import java.net.url; public class Example { public static void main(string[] args) throws Exception { URL myhome = new URL("http://www.myhome.net:8080"); URL gayo = new URL(myHome,"music/gayo/index.html"); System.out.println(gayo.getHost()); System.out.println(gayo.getFile()); 7. 웹서버에폼데이터나파일을업로드할때사용하는클래스는? 8. 다음코드에대한설명으로틀린것은? Socket so = new Socket("192.168.0.115", 5050); 1 클라이언트소켓객체를생성한다. 2 클라이언트가접속할서버의주소는 192.168.0.115이다. 3 생성된클라언트소켓의포트번호는 5050이다. 4 소켓객체가생성되면자동으로서버주소로자동접속이이루어진다.
820 JAVA 자바프로그래밍 JAVA PROGRAMMING 9. 다음은소켓을이용한네트워크프로그래밍에서클라이언트와서버가데이터통신하는과정이다. 2번에서필요한메소드는? 1 서버는특정포트번호로서버소켓생성 2 서버는클라이언트연결요청기다림 3 클라이언트는접속할서버주소와포트로클라이언트소켓생성하여서버에접속 4 서버와클라이언트모두소켓에서입출력스트림생성 5 서버와클라이언트데이터송수신 6 네트워크접속종료 실습문제 1. URLConnection 클래스를이용하여네이버홈페이지의데이터를읽어화면에출력하는프로그램을작성하라. 2. 클라이언트에서키입력한내용이그대로서버콘솔에출력되는프로그램을작성하라. 클라이언트가 끝 을입력하면클라이언트와서버모두종료하라. 3. 클라이언트에서산술연산을서버에보내면서버는연산을수행하여결과를클라이언트에전송하는프로그램을작성하라. 연산자는 +, -, *, / 으로제한하며피연산자및결과는 double 타입의숫자로한다. 서버에수식을전송할때 = 은포함하지않는다. 4. 클라이언트에서서버로바이너리파일을전송하여서버에똑같은사본을저장하는프로그램을작성하라. 클라이언트와서버는다음과같은간단한프로토콜을이용하라. 편의상클라이언트는서버에게명령과인자를오류없이전송하는것으로간주하고오류복구를위한재전송은없는것으로한다. 명령 (1 바이트 ) FILE_NAME(0x00) 명령인자 첫 4 바이트 ( 파일이름바이트크기 ), 파일이름 FILE_SIZE(0x01) 파일크기 (8 바이트 ) SEND_BEGIN(0x02) SEND_END(0x03) 인자없음 인자없음