명품 Java Essential 1
2 학습목표 1. 소켓통신에대한이해 2. 자바로간단한소켓통신프로그램작성
TCP/IP 소개 3 TCP/IP 프로토콜 두시스템간에데이터가손상없이안전하게전송되도록하는통신프로토콜 TCP 에서동작하는응용프로그램사례 e-mail, FTP, 웹 (HTTP) 등 TCP/IP 특징 연결형통신 한번연결후계속데이터전송가능 보낸순서대로받아응용프로그램에게전달
IP 주소 4 IP 주소 네트워크상에서유일하게식별될수있는컴퓨터주소 숫자로구성된주소 4 개의숫자가. 으로연결 예 ) 192.156.11.15 숫자로된주소는기억하기어려우므로 www.naver.com 과같은문자열로구성된도메인이름으로바꿔사용 DNS(Domain Name System) 문자열로구성된도메인이름을숫자로구성된 IP 주소로자동변환 현재는 32 비트의 IP 버전 4(IPv4) 가사용되고있음 IP 주소고갈로인해 128 비트의 IP 버전 6(IPv6) 이점점사용되는추세 자신의 IP 주소를간단히 localhost 라는이름으로사용가능
내컴퓨터의 IP 주소확인하기 5 내컴퓨터의윈도우에서명령창을열어 ipconfig 명령수행
6 통신하는프로그램간에가상의연결단생성 IP 주소는네트워크상의컴퓨터또는시스템을식별하는주소 번호를이용하여통신할응용프로그램식별 모든응용프로그램은하나이상의생성가능 를이용하여상대방응용프로그램과데이터교환 잘알려진 (well-known ports) 시스템이사용하는번호 잘알려진응용프로그램에서사용하는번호 0 부터 1023 사이의번호 ex) SSH 22, HTTP 80, FTP 21 잘알려진번호는 개발자가사용하지않는것이좋음 충돌가능성있음
를이용한통신 7. putty 터미날 3522 22 리눅스서버 컴퓨터 1(IP: 203.1.1.110) 크롬브라우저 2451 인터넷 80 1883 HTTP 웹서버 MQTT 브로커 컴퓨터 2(IP: 113.25.67.211) 컴퓨터 3(IP: 113.67.23.120)
소켓프로그래밍 8 소켓 (socket) TCP/IP 네트워크를이용하여쉽게통신프로그램을작성하도록지원하는기반기술 소켓 두응용프로그램간의양방향통신링크의한쪽끝단 소켓끼리데이터를주고받음 소켓은특정 IP 번호와결합 자바로소켓통신할수있는라이브러리지원 소켓종류 : 서버소켓과클라이언트소켓 웹브라우저 소켓 4289 인터넷 80 소켓 웹서버
소켓을이용한웹서버와클라이언트사이의통신사례 9 웹브라우저 클라이언트소켓 4289 클라이언트소켓 프로그램. 인터넷 80. 프로그램 웹브라우저 클라이언트소켓 4300 서버소켓 운영체제 웹서버
10 소켓을이용한서버클라이언트통신프로그램의전형적인구조
Socket 클래스, 클라이언트소켓 11 Socket 클래스 클라이언트소켓에사용되는클래스 java.net 패키지에포함 생성자
12 Socket 클래스의메소드
클라이언트에서소켓으로서버에접속하는코드 13 클라이언트소켓생성및서버에접속 Socket clientsocket = new Socket("128.12.1.1", 9999); Socket 의생성자에서 128.12.1.1 의주소의 9999 에접속 소켓으로부터데이터를전송할입출력스트림생성 BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); BufferedWriter out = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream())); 서버로데이터전송 flush() 를호출하면스트림속에데이터모두전송 서버로부터데이터수신 네트워크접속종료 out.write("hello"+"\n"); out.flush(); String line = in.readline(); // 서버로부터한행의문자열수신 clientsocket.close();
ServerSocket 클래스, 서버소켓 14 ServerSocket 클래스 서버소켓에사용되는클래스, java.net 패키지에포함 생성자 메소드
listen listen listen 서버에클라이언트가연결되는과정 15 서버는서버소켓으로들어오는연결요청을기다림 (listen) 서버 클라이언트가서버에게연결요청 서버 연결요청 클라이언트 1 서버가연결요청수락 (accept) 새로운클라이언트소켓을만들어클라이언트와통신하게함 그리고다시다른클라이언트의연결을기다림 서버 다른클라이언트로부터연결요청 클라이언트 2 클라이언트 연결 클라이언트 1
서버가클라이언트와통신하는과정 16 서버소켓생성 ServerSocket serversocket = new ServerSocket(9999); 서버는 9999 에서접속기다리는로 9999 선택 클라이언트로부터접속기다림 Socket socket = serversocket.accept(); accept() 메소드는접속요청이오면접속후새 Socket 객체반환 접속후새로만들어진 Socket 객체를통해클라이언트와통신 네트워크입출력스트림생성 BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); BufferedWriter out = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())); Socket 객체의 getinputstream() 과 getoutputstream() 메소드를이용하여입출력데이터스트림생성
서버 - 클라이언트채팅프로그램만들기 17 간단한채팅프로그램 서버와클라이언트가 1:1로채팅 클라이언트와서버가서로한번씩번갈아가면서문자열전송 문자열끝에 "\n" 을덧붙여보내고라인단위로수신 클라이언트가 bye를보내면프로그램종료
서버프로그램 ServerEx.java 18 import java.io.*; import java.net.*; import java.util.*; public class ServerEx { public static void main(string[] args) { BufferedReader in = null; BufferedWriter out = null; ServerSocket listener = null; Socket socket = null; Scanner scanner = new Scanner(System.in); // 키보드에서읽을 scanner 객체생성 try { listener = new ServerSocket(9999); // 서버소켓생성 System.out.println(" 연결을기다리고있습니다..."); socket = listener.accept(); // 클라이언트로부터연결요청대기 System.out.println(" 연결되었습니다."); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); while (true) { String inputmessage = in.readline(); // 클라이언트로부터한행읽기 if (inputmessage.equalsignorecase("bye")) { System.out.println(" 클라이언트에서 bye 로연결을종료하였음 "); break; // "bye" 를받으면연결종료 System.out.println(" 클라이언트 : " + inputmessage); System.out.print(" 보내기 >>"); // 프롬프트 String outputmessage = scanner.nextline(); // 키보드에서한행읽기 out.write(outputmessage + "\n"); // 키보드에서읽은문자열전송 out.flush(); // out 의스트림버퍼에있는모든문자열전송 catch (IOException e) { System.out.println(e.getMessage()); finally { try { scanner.close(); // scanner 닫기 socket.close(); // 통신용소켓닫기 listener.close(); // 서버소켓닫기 catch (IOException e) { System.out.println(" 클라이언트와채팅중오류가발생했습니다.");
클라이언트프로그램 ClientEx.java 19 import java.io.*; import java.net.*; import java.util.*; public class ClientEx { public static void main(string[] args) { BufferedReader in = null; BufferedWriter out = null; Socket socket = null; Scanner scanner = new Scanner(System.in); // 키보드에서읽을 scanner 객체생성 try { socket = new Socket("localhost", 9999); // 클라이언트소켓생성. 서버에연결 in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); while (true) { System.out.print(" 보내기 >>"); // 프롬프트 String outputmessage = scanner.nextline(); // 키보드에서한행읽기 if (outputmessage.equalsignorecase("bye")) { out.write(outputmessage+"\n"); // "bye" 문자열전송 out.flush(); break; // 사용자가 "bye" 를입력한경우서버로전송후실행종료 out.write(outputmessage + "\n"); // 키보드에서읽은문자열전송 out.flush(); // out 의스트림버퍼에있는모든문자열전송 String inputmessage = in.readline(); // 서버로부터한행수신 System.out.println(" 서버 : " + inputmessage); catch (IOException e) { System.out.println(e.getMessage()); finally { try { scanner.close(); if(socket!= null) socket.close(); // 클라이언트소켓닫기 catch (IOException e) { System.out.println(" 서버와채팅중오류가발생했습니다.");
채팅동작과정 연결대기 연결 사용자입력 안녕 \n 전송 너도안녕 \n 전송 사용자입력 사용자입력 20 프로그램종료 bye\n 전송 프로그램종료
수식계산서버 - 클라이언트만들기실습 21 문제개요 서버클라이언트는 1:1 통신 서버를먼저실행시키고, 클라이언트를실행시켜서버에접속 클라이언트는사용자로부터수식을입력받아서버로전송 연산자는 +, -, * 의 3 가지만허용하고정수연산만가능 서버가식을받으면식을서버의화면에출력하고, 계산하여결과를클라이언트로전송 클라이언트는서버로부터받은답을화면에출력 클라이언트와서버는전송할데이터를문자열로만들고 "\n" 을덧붙여전송하며, 라인단위로송수신 클라이언트가 "bye" 를보내면양쪽모두종료
22 실행예시
서버프로그램 CalcServerEx.java import java.io.*; import java.net.*; import java.util.*; public class CalcServerEx { public static String calc(string exp) { StringTokenizer st = new StringTokenizer(exp, " "); if (st.counttokens()!= 3) return "error"; String res=""; int op1 = Integer.parseInt(st.nextToken()); String opcode = st.nexttoken(); int op2 = Integer.parseInt(st.nextToken()); switch (opcode) { case "+": res = Integer.toString(op1 + op2); break; case "-": res = Integer.toString(op1 - op2); break; case "*": res = Integer.toString(op1 * op2); break; default : res = "error"; return res; public static void main(string[] args) { BufferedReader in = null; BufferedWriter out = null; ServerSocket listener = null; Socket socket = null; try { listener = new ServerSocket(9999); // 서버소켓생성 System.out.println(" 연결을기다리고있습니다..."); socket = listener.accept(); // 클라이언트로부터연결요청대기 System.out.println(" 연결되었습니다."); in = new BufferedReader( new InputStreamReader(socket.getInputStream())); out = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())); while (true) { String inputmessage = in.readline(); if (inputmessage.equalsignorecase("bye")) { System.out.println(" 클라이언트에서연결을종료하였음 "); break; // "bye" 를받으면연결종료 System.out.println(inputMessage); // 받은메시지를화면에출력 String res = calc(inputmessage); // 계산. 계산결과는 res out.write(res + "\n"); // 계산결과문자열전송 out.flush(); catch (IOException e) { System.out.println(e.getMessage()); finally { try { if(socket!= null) socket.close(); // 통신용소켓닫기 if(listener!= null) listener.close(); // 서버소켓닫기 catch (IOException e) { System.out.println(" 클라이언트와채팅중오류가발생했습니다."); 23
클라이언트프로그램 CalcClientEx.java 24 import java.io.*; import java.net.*; import java.util.*; public class CalcClientEx { public static void main(string[] args) { BufferedReader in = null; BufferedWriter out = null; Socket socket = null; Scanner scanner = new Scanner(System.in); try { socket = new Socket("localhost", 9999); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); while (true) { System.out.print(" 계산식 ( 빈칸으로띄어입력, 예 :24 + 42)>>"); // 프롬프트 String outputmessage = scanner.nextline(); // 키보드에서수식읽기 if (outputmessage.equalsignorecase("bye")) { out.write(outputmessage+"\n"); // "bye" 문자열전송 out.flush(); break; // 사용자가 "bye" 를입력한경우서버로전송후연결종료 out.write(outputmessage + "\n"); // 키보드에서읽은수식문자열전송 out.flush(); String inputmessage = in.readline(); // 서버로부터계산결과수신 System.out.println(" 계산결과 : " + inputmessage); catch (IOException e) { System.out.println(e.getMessage()); finally { try { scanner.close(); if(socket!= null) socket.close(); // 클라이언트소켓닫기 catch (IOException e) { System.out.println(" 서버와채팅중오류가발생했습니다.");