-
java 네트워크 프로그래밍대학/객체지향프로그래밍 2022. 12. 10. 19:32
- 네트워크 기초
소켓: 프로세스 간 통신 채널의 엔드 포인트
포트: 호스트 내부에서 소켓을 구분할 때 사용 (0~65535)
( 21: FTP / 23: Telnet / 43: whois / 80: HTTP / 443: HTTPS )
프로토콜: 통신간 데이터 전송 규약
IP: 네트워크 계층 프로토콜 ( IPv4(1*4바이트) / IPv6(2*8바이트) )
도메인: 호스트를 식별하는 이름으로 IP주소 대신 사용. 단, DNS 서버에 도메인이름-IP주소가 저장되어야 한다.
TCP: 연결 지향 전송 계층 프로토콜 (Handshake가 있고, 데이터 송수신 체크를 하기 때문에 신뢰성이 높다)
UDP: 비 연결 지향 전송 계층 프로토콜 (Handshake가 없고, 데이터 송수신 체크를 안 하기 때문에 속도가 빠르다)
import java.net.*; class InetAddressTest { public static void main(String[] args) throws UnknownHostException { InetAddress Address = InetAddress.getLocalHost(); System.out.println(Address); Address = InetAddress.getByName("www.google.com"); System.out.println(Address); InetAddress[] SW = InetAddress.getAllByName("www.naver.com"); for (int i = 0; i < SW.length; i++) System.out.println(SW[i]); } }
InetAddress의 정적 메서드를 이용해 도메인/IP를 가져올 수 있다.
분산 서비스를 하는 호스트의 경우 하나의 도메인에 여러 IP주소를 받아올 수 있다.
- 소켓 통신
1. Socket
클라이언트를 위한 소켓 클래스로 도메인과 포트를 인자로 소켓 객체를 생성할 수 있다.
소켓 객체에 I/O스트림을 통해 데이터를 주고 받을 수 있다.
import java.net.*; import java.io.*; class Whois { public static void main(String[] args) throws Exception { int c; Socket s = new Socket("whois.internic.net", 43); InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream(); String str = (args.length == 0 ? "google.com" : args[0]) + "\n"; byte[] buf = str.getBytes(); out.write(buf); while ((c = in.read()) != -1) { System.out.print((char) c); } s.close(); } }
2. ServerSocket
서버를 위핸 소켓 클래스로 서버는 클라이언트의 연결을 기다리기게 포트만을 인자로 소켓 객체를 생성한다.
// Server import java.io.*; import java.net.*; public class EchoServer { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(9999); // 이 프로세스 종료시 타임아웃 없이 바로 다른 프로세스가 포트번호를 사용할 수 있도록 혀용 server.setReuseAddress(true); Socket connection = server.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String msg = null; while ((msg = in.readLine()) != null) { System.out.println("Received: " + msg); } in.close(); connection.close(); server.close(); } } // Client import java.io.*; import java.net.*; import java.util.Scanner; public class EchoClient { public static void main(String[] args) throws IOException { try { Socket client = new Socket(); client.connect(new InetSocketAddress("localhost", 9999), 8888); PrintWriter out = new PrintWriter(client.getOutputStream(), true); Scanner in = new Scanner(System.in); String msg; System.out.print("Type: "); while ((msg = in.nextLine()) != null) { if (msg.contains("end")) break; out.println(msg); } out.close(); in.close(); client.close(); } catch (Exception e) { System.out.println(e); } } }
위 코드(에코서버 구현)의 흐름을 살펴보자.
1. 서버에서 9999포트로 서버를 실행했다.
2. 클라이언트에서 127.0.0.1(localhost):9999에 연결. 클라이언트 본인은 8888번 포트 사용.
3. server.accept()에서 9999포트로 들어온 연결을 다른 포트(10000?)로 연결해주며 새로운 소켓 객체를 생성.
4. I/O스트림을 이용해 데이터 송수신
5. end 입력시 클라이언트 소켓이 닫힘
6. 클라이언트 소캣과의 연결이 끊어진 서버는 in.readLine()이 null값이 되기에 소켓이 닫힘
- TCP통신 예시
웹 관련 프로토콜(e.g. http)을 사용할 때, URL이라는 식별자로 웹 페이지의 주소를 지정하는데,
이 URL객체를 만들어보자.
import java.net.*; class URLDemo { public static void main(String[] args) throws MalformedURLException { URL hp = new URL("https://cs.kw.ac.kr:501/main/main.php"); // 광운대 사랑해요 <3 System.out.println("Protocol: " + hp.getProtocol()); System.out.println("Port: " + hp.getPort()); System.out.println("Host: " + hp.getHost()); System.out.println("File: " + hp.getFile()); System.out.println("Ext: " + hp.toExternalForm()); } } // Protocol: https // Port: 501 // Host: cs.kw.ac.kr // File: /main/main.php // Ext: https://cs.kw.ac.kr:501/main/main.php
URL에는 프로토콜, 호스트, 포트, 파일 등 여려 정보가 담기는데,
URL객체는 이 정보를 잘 파싱해주는 메서드들을 제공한다.
import java.net.*; import java.io.*; import java.util.Date; class UCDemo { public static void main(String[] args) throws Exception { int c; URL hp = new URL("http://www.google.com"); URLConnection hpCon = hp.openConnection(); System.out.println("Date: " + new Date(hpCon.getDate())); System.out.println("Content-Type: " + hpCon.getContentType()); System.out.println("Expires: " + new Date(hpCon.getExpiration())); System.out.println("Last-Modified: " + new Date(hpCon.getLastModified())); long len = hpCon.getContentLengthLong(); System.out.println("Content-Length: " + len); if (len != 0) { System.out.println("=== Content ==="); InputStream input = hpCon.getInputStream(); while (((c = input.read()) != -1)) { System.out.print((char) c); } input.close(); } else { System.out.println("No content available."); } } } // Date: Sat Dec 10 19:08:09 KST 2022 // Content-Type: text/html; charset=ISO-8859-1 // Expires: Thu Jan 01 09:00:00 KST 1970 // Last-Modified: Thu Jan 01 09:00:00 KST 1970 // ...
URLConnection객체는 URL객체를 기반으로 만드는데,
여러 메서드를 사용해서 HTTP Response의 헤더와 페이로드를 파싱한 값을 받아올 수 있다.
import java.net.*; import java.util.*; class HttpURLDemo { public static void main(String[] args) throws Exception { URL hp = new URL("http://www.google.com"); HttpURLConnection hpCon = (HttpURLConnection) hp.openConnection(); System.out.println("Request method is " + hpCon.getRequestMethod()); System.out.println("Response code is " + hpCon.getResponseCode()); System.out.println("Response Message is " + hpCon.getResponseMessage()); Map<String, List<String>> hdrMap = hpCon.getHeaderFields(); Set<String> hdrField = hdrMap.keySet(); System.out.println("\nHere is the header:"); for (String k : hdrField) { System.out.println("Key: " + k + " Value: " + hdrMap.get(k)); } } } // Request method is GET // Response code is 200 // Response Message is OK // ...
HttpURLConnection은 URLConnection 클래스를 상속받는 클래스로
HTTP와 관련된 메서드들이 정의되어있다.
import java.net.*; import java.net.http.*; import java.io.*; class HttpClientDemo { public static void main(String[] args) throws Exception { HttpClient myHC = HttpClient.newHttpClient(); HttpRequest myReq = HttpRequest.newBuilder(new URI("http://www.google.com/")).build(); HttpResponse<InputStream> myResp = myHC.send(myReq, HttpResponse.BodyHandlers.ofInputStream()); System.out.println("Response code is " + myResp.statusCode()); System.out.println("Request method is " + myReq.method()); HttpHeaders hdrs = myResp.headers(); ...
java.net.http에 포함된 API로 위의 코드와 같은 기능을 구현.
하지만, 최신 기술이 더 적용된 코드이다.
- UDP통신 예시
import java.net.*; class WriteServer { public static int serverPort = 1099; public static int clientPort = 1098; public static int buffer_size = 1024; public static DatagramSocket ds; public static byte[] buffer = new byte[buffer_size]; public static void TheServer() throws Exception { int pos = 0; while (true) { int c = System.in.read(); switch (c) { case 'q': System.out.println("Server Quits."); ds.close(); return; case '\r': break; case '\n': ds.send(new DatagramPacket(buffer, pos, InetAddress.getByName("127.0.0.1"), clientPort)); pos = 0; break; default: buffer[pos++] = (byte) c; } } } public static void TheClient() throws Exception { while (true) { DatagramPacket p = new DatagramPacket(buffer, buffer.length); ds.receive(p); System.out.println(new String(p.getData(), 0, p.getLength())); } } public static void main(String[] args) throws Exception { if (args.length == 1) { ds = new DatagramSocket(serverPort); ds.setReuseAddress(true); TheServer(); } else { ds = new DatagramSocket(clientPort); ds.setReuseAddress(true); TheClient(); } } }
DatagramSocket 클래스는 UDP로 전송 계층 프로토콜을 사용하기 위해 생성하는 소켓 클래스이고,
DatagramPacket 클래스틑 UDP 클라이언트-서버 간 주고 받는 패킷을 담는 클래스이다.
'대학 > 객체지향프로그래밍' 카테고리의 다른 글
java collection framework (0) 2022.12.10 java lambda expression / 메서드 참조 (0) 2022.12.10 java generic(2) (0) 2022.12.10 java generic(1) (0) 2022.12.09 java transient / volatile / instanceof / native / assert (0) 2022.12.09