Chapter 16 네트워킹(Networking)
1. 네트워킹(Networking)
- 네트워킹(networking)이란 두 대 이상의 컴퓨터를 케이블로 연결하여 네트워크network)를 구성하는 것을 말한다
1.1 클라이언트/서버(client/server)
- '클라이언트/서버는 컴퓨터간의 관계를 역할로 구분하는 개념이다 서버(server)는 서비스를 제공하는 컴퓨터(service provider)이고 클라이언트(client)는 서비스를 사용하는 컴퓨터(service user)가 된다.
- 네트워크를 구성할 때 전용서버를 두는 것을 서버기반모델 이라고 하고 각 클라이언트가 서버역할을 동시에 수행하는 것을 P2P모델 이라고 한다
- 서버는 제공하는 서비스의 종류에 따라 파일서버 메일서버, 어플리케이션 서버 등이 있다
서버기반 모델(server-based model) | P2P 모델(peer-to-peer model) |
---|---|
안정적인 서비스의 제공이 가능하다 | 서버구축 및 운용비용을 절감할 수 있다 |
공유 데이터의 관리와 보안이 용이 하다 | 자원의 활용을 극대화 할 수 있다 |
서버구축비용과 관리비용이 든다 | 자원의 관리가 어렵다 |
서버구축비용과 관리비용이 든다 | 보안이 취약하다 |
1.2 IP주소(IP Address)
- IP주소는 컴퓨터를 네트워크 상에서 구별하는데 사용되는 고유한 값이며 4byte(32 bit)의 정수로 구성되어 있다
- IP주소는 네트워크주소와 호스트 주소로 누눌 수 있으며 네트워크 주소가 같다는 것은 두 호스트가 같은 네트워크에 포함되어 있다는 것을 의미한다
- IP Address에 Subnet Mask를 '&'연산을 해주면 네트워크 주소를 알 수 있다
| 192 | 168 | 10 | 100 | | 255 | 255 | 255 | 0 | |--|--|--|--| |11000000|10101000|00001010|01100100| |11111111|11111111|11111111|00000000| |11000000|10101000|00001010|01100100|
1.3 InetAddress
- 자바에서는 IP주소를 다루기 위한 클래스로 InetAddress를 제공한다
import java.net.*;
import java.util.*;
public class Hello {
public static void main(String[] args) {
InetAddress ip = null;
InetAddress[] ipArr = null;
try{
ip = InetAddress.getByName("www.daum.net");
System.out.println("getHostName() :" + ip.getHostName());
System.out.println("getHostAddress() :" + ip.getHostAddress());
System.out.println("toString() :" + ip.toString());
byte[] ipAddr = ip.getAddress();
System.out.println("getAddress() :" + Arrays.toString(ipAddr));
String result = "";
for (int i=0; i < ipAddr.length; i++) {
result += (ipAddr[i] < 0) ? ipAddr[i] + 256 : ipAddr[i];
result += ".";
}
System.out.println("getAddress() + 256 :" + result);
System.out.println();
}
catch(UnknownHostException e){
e.printStackTrace();
}
try{
ip = InetAddress.getLocalHost();
System.out.println("getHostName() :" + ip.getHostName());
System.out.println("getHostAddress() :" + ip.getHostAddress());
System.out.println();
}
catch(UnknownHostException e){
e.printStackTrace();
}
try{
ipArr = InetAddress.getAllByName("www.daum.net");
for (int i=0; i < ipArr.length; i++) {
System.out.println("ipArr["+i+"]" + ipArr[i]);
}
}
catch(UnknownHostException e){
e.printStackTrace();
}
}
}
getHostName() :www.daum.net
getHostAddress() :117.52.2.25
toString() :www.daum.net/117.52.2.25
getAddress() :[117, 52, 2, 25]
getAddress() + 256 :117.52.2.25.
getHostName() :KyleYui-MacBook-Pro.local
getHostAddress() :192.168.99.1
ipArr[0]www.daum.net/117.52.2.25
ipArr[1]www.daum.net/61.111.62.165
1.4 URL(Uniform Resource Location)
- URL은 인터넷에 존재하는 여러 서버들이 제공하는 자원에 접근할 수 있는 주소를 표현하기 위한것
- '프로토콜//호스트명:포트번호/경로명/파일명?쿼리스트링#참조' 형태로 이루어져 있다
http://www.codechobo.com:80/sample/hello.html?referer=codechobo#index1
프로토콜 자원에 접근하기 위해 서버와 통신하는데 사용되는 통신규약(http)
호스트명 자원을 제공하는 서버의 이름(www.javachobo.com)
포트번호 통신에 사용되는 서버의 포트번호(80)
경로명 접근하려는 자원이 저장된 서버상의 위치(/sample)
파일명 접근하려는 자원의 이름(hello.html)
쿼리query) URL에서 '?'이후의 부분(referer=javachobo)
참조(anchor) URL에서 '#'이후의 부분(index1)
import java.net.URL;
public class Main {
public static void main(String[] args) {
try {
URL url = new URL("http://media.daum.net/mainnews/?type=sports#index1");
System.out.println("url.getAuthority() :" + url.getAuthority());
System.out.println("url.getContent() :" + url.getContent().toString());
System.out.println("url.getDefaultPort() :" + url.getDefaultPort());
System.out.println("url.getPort() :" + url.getPort());
System.out.println("url.getFile() :" + url.getFile());
System.out.println("url.getHost() :" + url.getHost());
System.out.println("url.getPath() :" + url.getPath());
System.out.println("url.getProtocol() :" + url.getProtocol());
System.out.println("url.getQuery() :" + url.getQuery());
System.out.println("url.getRef() :" + url.getRef());
System.out.println("url.getUserInfo() :" + url.getUserInfo());
System.out.println("url.toExternalForm() :" + url.toExternalForm());
System.out.println("url.toURI() :" + url.toURI());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
url.getAuthority() :media.daum.net
url.getContent() :sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@5e2de80c
url.getDefaultPort() :80
url.getPort() :-1
url.getFile() :/mainnews/?type=sports
url.getHost() :media.daum.net
url.getPath() :/mainnews/
url.getProtocol() :http
url.getQuery() :type=sports
url.getRef() :index1
url.getUserInfo() :null
url.toExternalForm() :http://media.daum.net/mainnews/?type=sports#index1
url.toURI() :http://media.daum.net/mainnews/?type=sports#index1
1.5 URLConnection
- URLConnection은 어플리케이션과 URL간의 통신연결을 나타내는 클래스의 최상위 클래스로 추상클래스이다.
- URLConnection을 상속받아 구현한 클래스로는 HttpURLConnection과 JarURLConnection이 있으며 URL의 프로토콜이 http프로토콜이라면 openConnection()은 Http URLConnection을 반환한다.
- https://docs.oracle.com/javase/8/docs/api/java/net/URLConnection.html
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
public class Main {
public static void main(String[] args) {
URL url = null;
BufferedReader input = null;
String address = "http://www.codechobo.com";
String line = "";
try {
url = new URL(address);
input = new BufferedReader(new InputStreamReader(url.openStream()));
while ((line = input.readLine()) != null){
System.out.println(line);
}
input.close();
} catch (MalformedURLException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv='refresh' content='0;url=http://www.codechobo.com/main'>
<title>코드초보</title>
</head>
<body>
</body>
</html>
- 데이터가 문자데이터 이기 때문에 BefferedReader를 사용함
- url.openStream()은 url.openConnectino().getInputStream() 과 같다
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
public class Main {
public static void main(String[] args) {
URL url = null;
InputStream in = null;
FileOutputStream out = null;
String address = "http://www.codechobo.com";
int ch = 0;
try {
url = new URL(address);
in = url.openStream();
out = new FileOutputStream("javajungsuk.zip");
while( (ch=in.read()) != -1){
out.write(ch);
}
in.close();
out.close();
} catch (MalformedURLException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Helloworld.class Helloworld.java Java Test.iml javajungsuk.zip out src
- 텍스트가 아닌 이진 데이터를 읽어서 파일에 저장하는 예제
2. 소켓 프로그래밍
- 소켓(socket)
- 네트워크의 양방향 통신에서 양쪽 끝단으로, TCP/IP 단에서 구분할 수 있는 하나의 포트 번호를 가진다.
- Java의 소켓 프로그래밍
- java.net 패키지가 소켓 프로그래밍 클래스들을 제공한다.
2.1 TCP와 UDP
- TCP/UDP
- TCP와 UDP 모두 TCP/IP 프로토콜에 포함되어있는 프로토콜로, OSI 7계층의 전송 계층(transport layer)에 해당하는 프로토콜이다.
- TCP와 UDP의 특징
항목 | TCP | UDP |
---|---|---|
연결방식 | 연결 기반, 1:1 통신 | 비연결기반, 1:1 / 1:n / n:n 통신 |
특징 | 바이트 단위로 전송, 신뢰성 기반: 전송 순서 보존 / 수신 여부 확인 | 데이터 단위로 전송, 신뢰성이 없다 |
클래스 | Socket, ServerSocket | DatagramSocket, DatagramPacket, MulticastSocket |
2.2 TCP소켓 프로그래밍
- 서버/클라이언트의 통신 과정
- [서버] ServerSocket으로 특정 포트로 소켓을 연다.
- [클라이언트] 서버의 IP 주소와 포트로 Socket으로 소켓을 만들어 서버에 연결 요청을 한다.
- [서버] 클라이언트의 연결 요청을 받으면 Socket으로 소켓을 만들어 클라이언트의 소켓과 연결한다.
- [서버/클라이언트] 연결된 각자의 소켓을 이용해 통신을 한다.
- 소켓
- 여러 소켓이 포트 하나를 공유할 수 있지만, 서버소켓은 포트 하나를 독점한다.
- 소켓은 입력스트림과 출력스트림을 가지고 상대방 소켓과 서로 교차연결해 데이터를 주고받는다.
서버 예제
- 쓰레드로 통신하기
class Sender extends Thread { DataOutputStream out; ... Sender(Socket socket) { ... out = new DataOutputStream(socket.getOutputStream()); ... } public void run() { ... out.writeUTF("Sender message."); ... } }
class Receiver extends Thread { DataInputStream in; ... Receiver(Socket socket) { ... in = new DataInputStream(socket.getInputStream()); ... } public void run() { ... System.out.println(in.readUTF()); ... } }
서버
ServerSocket serverSocket = new ServerSocket(7777); Socket socket = serverSocket.accept(); // 클라이언트의 연결 요청을 받아 통신용 소켓을 만든다. Sender sender = new Sender(socket); Receiver receiver = new Receiver(socket); sender.start(); receiver.start();
클라이언트
Socket socket = new Socket("127.0.0.1", 7777); Sender sender = new Sender(socket); Receiver receiver = new Receiver(socket); sender.start(); receiver.start();
- 쓰레드로 통신하기
2.3 UDP소켓 프로그래밍
- 특징
- 연결지향이 아니므로 ServerSocket이 따로 필요하지 않다.
- 소켓은 DatagramSocket를 사용해 만들어 DatagramPacket에 데이터를 담아 통신한다.
- DatagramPacket에는 헤더와 데이터가 있으며 헤더에 수신할 상대방의 정보(주소와 포트)를 저장한다.
예제
서버
DatagramSocket datagramSocket = new DatagramSocket(7777); byte[] inMsg = new byte[10]; // (데이터, 데이터 길이) - 받을 패킷 만들기 DatagramPacket inPacket = new DatagramPacket(inMsg, inMsg.length); socket.receive(inPacket); System.out.println(new String(inPacket.getData()); dataSocket.close();
클라이언트
// 클라이언트는 포트를 지정하지 않는다. DatagramSocket datagramSocket = new DatagramSocket(); InetAddress serverAddress = InetAddress.getByName("127.0.0.1"); byte[] msg = new byte[10]; // (데이터, 데이터 길이, 주소, 포트) - 보낼 패킷 만들기 DatagramPacket outPacket = new DatagramPacket(msg, msg.length, serverAddress, 7777); datagramSocket.send(outPacket); datagramSocket.close();