네트워크 기초
네트워크 : 여러 대의 컴퓨터를 통신 회선으로 연결한 것
인터넷 : 지역 네트워크를 통신 회선으로 연결한 것
참고 : 생활코딩 작심삼일 프로젝트 : 서버란 무엇인가? (https://www.opentutorials.org/module/638/5201)
서버와 클라이언트
클라이언트 : 서비스를 받는 프로그램 / 인터넷에서 서비스를 받기 위해 연결을 요청 (request)
Java 에서 IP주소 얻기
자바는 IP주소를 java.net.InetAddress 객체로 표현
로컬컴퓨터의 IP주소뿐만 아니라 도메인 이름을 DNS에서 검색한 후 IP주소를 가져오는 기능 제공
InetAddress ia = InetAddress.getLocalHost(); //로컴컴퓨터 아이피 리턴
InetAddress ia = InetAddress.getByName(String host); // 도메인 이름을 통해 아이피 얻기
연결 클라이언트가 많은 회사의 경우 서버의 과부하를 막기 위해 하나의 도메인 이름에 여러 개의 컴퓨터 IP를 등록해서 운영하기도 한다. 이 경우 DNS에 등록된 모든 IP주소를 얻고 싶다면 getAllByName() 메서드 사용. 리턴 타입은 InetAddress[ ]
InetAddress[ ] iaArr = InetAddress.getAllByName(String host); // 도메인 예시) www.naver.com
InetAddress 객체에서 IP주소를 얻을 때 : getHostAddress() 메서드가 문자열로 된 IP주소 리턴
String ip = InetAddress.getHostAddress();
※UnknownHostException 이 발생할 수 있으므로 예외처리한다.
TCP 네트워킹 (Transmission Control Protocol)
*프로토콜(protocol) : 컴퓨터간에 정보를 주고받을 때의 통신방법에 대한 규칙과 약속
TCP는 연결 지향적 프로토콜.
연결 지향적 프로토콜 :
클라이언트와 서버가 연결된 상태에서 데이터를 주고받는 프로토콜. 클라이언트가 연결 요청을 하고, 서버가 연결을 수락하면통시누선로가 고정되고, 모든 데이터는 고정된 통신 선로를 통해서 순차적으로 전달된다.
때문에 TCP 는 데이터를 정확하고 안정적으로 전달한다.
TCP의 단점
데이터를 보내기 전에 반드시 연결이 형성되어야 하고(가장 시간이 많이 걸리는 작업이다.)
고정된 통신 선로가 최단선(네트워크 길이 측면)이 아닐 경우 상대적으로 UDP(User Datagram Protocol)보다 데이터 전송 속도가 느릴 수 있다.
java는 TCP네트워킹을 위해 java.net.SeverSocket / java.net.Socket 클래스 제공
ServerSocket과 Socket의 용도
TCP 서버의 역할
1. 클라이언트가 연결 요청을 해오면 연결을 수락
2. 연결된 클라이언트와 통신
자바에서는 이 두 역할별로 별로의 클래스 제공
ServerSocket : 1. 연결 요청 기다리면서 연결 수락 담당
Socket : 2. 연결된 클라이언트와는 통신 담당
클라이언트가 연결 요청을 해오면 ServerSocket은 연결을 수락하고 통신용 Socket을 만든다.
통신을 위해 ServerSocket 생성할 때 포트를 하나 지정 (서버 바인딩 포트)
클라이언트는 Socket을 생성해서 서버의 IP주소와 바인딩 포트번호로 연결요청
accept() 메서드로 연결 수락하고 통신용 Socket 생성
서버와 클라이언트는 각각의 Socket을 이용하여 데이터를 주고 받는다.
1. 서버 소켓 생성과 연결 수락
2. (클라이언트) 소켓 생성과 연결 요청
3. 소켓 데이터 통신(데이터 보내고 받기)
1. 서버 소켓 생성과 연결 수락
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 39 40 41 42 43 | package networking; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; public class ServerExample { public static void main(String[] args) { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress("localhost", 5001)); while (true) { System.out.println("[연결 기다림]"); Socket socket = serverSocket.accept(); // 연결 수락하여 소켓 생성 InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress(); // getRemoteSocketAddress()의 리턴타입은 SocketAddress // : InetSocketAddress의 상위 클래스 System.out.println("[연결 수락함]"); } } catch (IOException e) { e.printStackTrace(); } if (!serverSocket.isClosed()) { try { serverSocket.close(); //서버 소켓 닫기 } catch (IOException e2) { } } } } | cs |
2. (클라이언트) 소켓 생성과 연결 요청
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 | package networking2; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; public class ClientExample { public static void main(String[] args) { Socket socket = null; try { socket = new Socket(); // (클라이언트) 소켓 생성 System.out.println("[연결 요청]"); socket.connect(new InetSocketAddress("localhost", 5001)); // 주어진 소켓주소로 연결 요청 // "localhost", 5001 : 현재 PC의 5001포트 System.out.println("[연결 성공]"); } catch (Exception e) { } if (!socket.isClosed()) { try { socket.close(); } catch (IOException e1) { } } } } | cs |
3. Socket 데이터 통신
클라이언트가 연결 요첨 ( connect() )하고 서버가 연결 수락 ( accept() )했다면
양쪽의 Socket 객체로부터 각각 입력 스트림(InputStream)과 출력 스트림(OutputStream)을 얻을 수 있다.
1) 클라이언트가 먼저 "Hello Server"를 서버로 보낸다
2) 서버가 이 데이터를 받고
3) "Hello Client"를 클리이언트로 보내면
4) 클라이언트가 이 데이터를 받는다.
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | package networking2; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; public class ClientExample { public static void main(String[] args) { Socket socket = null; try { // 2. (클라이언트)소켓 생성과 연결요청 socket = new Socket(); // (클라이언트) 소켓 생성 System.out.println("[연결 요청]"); socket.connect(new InetSocketAddress("localhost", 5001)); // 주어진 소켓주소로 연결 요청 // "localhost", 5001 : 현재 PC의 5001포트 System.out.println("[연결 성공]"); // 3.Socket 데이터 통신 // 3-1) 클라이언트가 먼저 message : "Hello Server"를 서버로 보낸다. byte[] bytes = null; // 출력할 정보 담을 바이트배열 String message = null; OutputStream os = socket.getOutputStream(); // 소켓을 통해 출력스트림 생성 message = "Hello Server"; bytes = message.getBytes("UTF-8"); // 메시지 문자열을 바이트 배열에 UTF-8 문자셋으로 저장 os.write(bytes);// 소켓 출력 스트림의 write(출력할 정보)로 데이터 보내기 // 이미 연결된 상태이기 때문에 주소(InetSocketAddress)를 따로 줄 필요가 없다 os.flush(); System.out.println("[데이터 보내기 성공]"); // 3-4)서버에게서 message : "Hello Client"를 받는다. InputStream is = socket.getInputStream(); bytes = new byte[100]; // 읽어오는 데이터를 저장할 바이트 배열 생성 int readByteCount = is.read(bytes); // 서버소켓의 입력스트림의 read(byte[])메서드로 읽은 데이터를 바이트배열에 저장하고 // 항목 수를 리턴한다. message = new String(bytes, 0, readByteCount, "UTF-8"); // 바이트 배열을 문자열 타입에 복사해서 문자열 참조변수인 메시지에 담는다. System.out.println("[데이터 받기 성공]" + message); } catch (Exception e) { } if (!socket.isClosed()) { try { socket.close(); } catch (IOException e1) { } } } } | cs |
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | package networking; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; public class ServerExample { public static void main(String[] args) { ServerSocket serverSocket = null; try { // 1. 서버소켓 생성과 연결 수락 serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress("localhost", 5001)); while (true) { System.out.println("[연결 기다림]"); Socket socket = serverSocket.accept(); // 연결 수락하여 소켓 생성 InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress(); // getRemoteSocketAddress()의 리턴타입은 SocketAddress // : InetSocketAddress의 상위 클래스 System.out.println("[연결 수락함]"); // 3.Socket 데이터 통신 // 3-2) 서버가 "Hello Server"메시지(데이터)를 받는다 byte[] bytes = null; // 출력할 정보 담을 바이트배열 String message = null; InputStream is = socket.getInputStream(); bytes = new byte[100]; // 읽어오는 데이터를 저장할 바이트 배열 생성 int readByteCount = is.read(bytes); // 서버소켓의 입력스트림의 read(byte[])메서드로 읽은 데이터를 바이트배열에 저장하고 // 항목 수를 리턴한다. message = new String(bytes, 0, readByteCount, "UTF-8"); // 바이트 배열을 문자열 타입에 복사해서 문자열 참조변수인 메시지에 담는다. System.out.println("[데이터 받기 성공]" + message); // 3-3)message : "Hello Client"를 클라이언트로 보낸다 OutputStream os = socket.getOutputStream(); // 소켓을 통해 출력스트림 생성 message = "Hello Client"; bytes = message.getBytes("UTF-8"); // 메시지 문자열을 바이트 배열에 UTF-8 문자셋으로 저장 os.write(bytes);// 소켓 출력 스트림의 write(출력할 정보)로 데이터 보내기 os.flush(); System.out.println("[데이터 보내기 성공]"); } } catch (IOException e) { e.printStackTrace(); } if (!serverSocket.isClosed()) { try { serverSocket.close(); // 서버 소켓 닫기 } catch (IOException e2) { } } } } | cs |
비연결 지향적 프로토콜 : 데이터를 주고받을 때 연결 절차를 거치지 않고, 발신자가 일방적으로 데이터를 발신하는 방식
연결과정이 없기 때문에 TCP보다 빠른 전송이 가능하지만 데이터 전달의 신뢰성은 떨어진다.
순차적으로 보낸다고 순차적으로 도착하진 않는다.
속도가 중요한 프로그램에서는 UDP를 사용하고
신뢰성이 중요한 프로그램에서는 TCP를 사용한다.
자바는 UDP 네트워킹을 위해 java.net.DatagramSocket과 java.net.DatagramPacket 클래스 제공
DatagramPacket 클래스
발신자 패킷 객체(데이터, 수신자 정보가 담김)를 생성
수신자 패킷 객체(읽은 데이터를 저장항 바이트 배열을 매개값으로) 생성
DatagramSocket 클래스
발신자 소켓 객체를 생성(매개값으로 포트넘버 안줘도 된다 = 포트바인딩 필요없다)하고
send(Packet객체) 메서드로 정보를 전송
수신자 소켓 객체(포트 바인딩 필요)를 생성하고 recieve(packet)메서드로 받은 데이터를 읽어온다
'Java > study' 카테고리의 다른 글
NIO기반 입출력 (0) | 2019.04.24 |
---|---|
스레드풀(ThreadPool) (0) | 2019.04.24 |
IO기반 입출력 (0) | 2019.04.22 |
병렬 처리 (스트림과 병렬처리 뒷부분) (0) | 2019.04.21 |
스트림과 병렬처리 (0) | 2019.04.20 |