16장 네트워킹

slee2·2021년 10월 10일
0

Java의 정석

목록 보기
28/28
post-thumbnail
post-custom-banner

네트워킹이 뭘까

두 대 이상의 컴퓨터를 케이블로 연결하여 네트워크(network)를 구성하는 것.

여기에서는 가장 기본적인 네트워킹 예제들과 채팅 어플리케이션을 작성할 수 있을 정도 수준의 내용만을 다룰 것이다.
이걸 발전시키면 메신저나 간다한 온라인게임을 내 손으로 해버리기.

클라이언트와 서버(client & server)

서버 : 서비스를 제공하는 컴퓨터.(service provider)
클라이언트 : 서비스를 사용하는 컴퓨터.(service user)
서비스 : 서버가 클라이언트로부터 요청받은 작업을 처리하여 그 결과를 제공한다는 뜻.
서비스의 종류에 따라 파일 서버, 메일 서버, 어플리케이션 서버 등이 있다.

일반 PC는 서버에 접속하는 클라이언트 역할을 하지만, 토랜트 같은 프로그램의 경우 클라이언트 프로그램서버 프로그램을 하나로 합친 것이다. 그래서 내가 파일 받을 수 있는 동시에 서버가 되어 다른 컴퓨터에게 파일을 제공할 수 있다.

네트워크를 구성할때 전용서버를 두는 것을 서버기반모델
전용서버 없이 클라이언트가 서버역할을 동시에 수행하는 것을 P2P모델이라고 한다.

서버기반 모델(server-based model)P2P 모델(peer-to-peer model)
- 안정적인 서비스의 제공이 가능하다.
- 공유 데이터의 관리와 보안이 용이하다.
- 서버구축비용과 관리비용이 든다.
- 서버구축 및 운용비용을 절감할 수 있다.
- 자원의 활용을 극대화 할 수 있다.
- 자원의 관리가 어렵다.
- 보안이 취약하다.

IP주소(IP address)

예시1 : 172.16.254.1/24
서브넷 마스크 24bit 씀 : 255.255.255.0
IP 주소 : 172.16.254.0
호스트 주소 : 1
클래스 : C

예시2 : 172.16.254.1/16
서브넷 마스크 16bit 씀 : 255.255.0.0
IP 주소 : 172.16.0.0
호스트 주소 : 254.1
클래스 : B

InetAddress 클래스

자바에서 IP 다루기 위해 쓰는 클래스

메서드설명
byte[] getAddress()IP주소를 byte배열로 반환한다.
static InetAddress[] getAIIByName(String host)도메인명(host)에 지정된 모든 호스트의 IP주소를 배열
에 담아 반환한다.
static InetAddress getByAddress(byte[] addr)byte배열을 통해 IP주소를 얻는다.
static InetAddress getByName(String host)도메인명(host)을 통해 IP주소를 얻는다.
String getCanonicalHostName()FQDN(fully qualified domain name)을 반환한다.
String getHostAddress()호스트의 IP주소를 반환한다.
String getHostName()호스트의 이름을 반환한다.
static InetAddress getLocalHost()지역 호스트의 IP주소를 반환한다.
boolean isMulticastAddress()IP주소가 멀티캐스트 주소인지 알려준다.
boolean isLoopbackAddress()IP주소가 loopback 주소(127.0.0.1)인지 알려준다.
import java.net.*;
import java.util.*;

class Ex16_1 {
    public static void main(String args[]) {
        InetAddress ip = null;
        InetAddress[] ipArr = null;

        try {
            ip = InetAddress.getByName("www.naver.com");
            System.out.println("getHostName() :" + ip.getHostName());
            // getHostName() :www.naver.com
            System.out.println("getHostAddress() :" + ip.getHostAddress());
            // getHostAddress() :223.130.195.95
            System.out.println("toString() :" + ip.toString());
            // toString() :www.naver.com/223.130.195.95

            byte[] ipAddr = ip.getAddress();
            System.out.println("getAddress() :" + Arrays.toString(ipAddr));
            // getAddress() :[-33, -126, -61, 95]

            String result = "";
            for(int i=0; i < ipAddr.length; i++)
                result += (ipAddr[i] < 0 ? ipAddr[i] + 256 : ipAddr[i])+".";
            System.out.println("getAddress()+256 :" + result);
            // getAddress()+256 :223.130.195.95.
            System.out.println();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        try {
            ip = InetAddress.getLocalHost();
            System.out.println("getHostName() :" + ip.getHostName());
            // getHostName() :seungjuui-MacBookPro.local
            System.out.println("getHostAddress() :" + ip.getHostAddress());
            // getHostAddress() :218.38.137.27
            System.out.println();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        try {
            ipArr = InetAddress.getAllByName("www.naver.com");

            for(int i=0; i<ipArr.length; i++)
                System.out.println("ipArr["+i+"] :"+ipArr[i]);
            // ipArr[0] :www.naver.com/223.130.195.95
            // ipArr[1] :www.naver.com/223.130.200.104
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}

URL(Uniform Resuorce Locator)

프로토콜 :// 호스트명 : 포트번호 / 경로명 / 파일명 ? 쿼리스트링 # 참조

http://www.codechobo.com:80/sample/hello.html?refer-codechobo#index1

프로토콜
자원에 접근하기 위해 서버와 통신하는데 사용되는 통신 규약
호스트명
자원을 제공하는 서버의 이름(www.~)
포트번호
통신에 사용되는 서버의 포트번호(80)
경로명
접근하려는 자원이 저장된 서버상의 위치(/sample/)
파일명
접근하려는 자원의 이름(hello.html)
쿼리(query)
URL에서 '?' 이후의 부분(refer=codechobo)
참조(anchor)
URL에서 '#' 이후의 부분(index1)

URL 클래스

클래스이름이 URL ㄷㄷ...

메서드설명
URL(String spec)지정된 문자열 정보의 URL 객체를 생성한다.
URL(String protocol, String host, String file)지정된 값으로 구성된 URL 객체를 생성한다.
URL(String protocol, String host, int port, String file)지정된 값으로 구성된 URL 객체를 생성한다.
String getAuthority()호스트명과 포트를 문자열로 반환한다.
Object getContent()URL의 Content객체를 반환한다.
Object getContent(Class[] classes)URL의 Content객체를 반환한다.
int getDefaultPort()URL의 기본 포트를 반환한다.(http는 80)
String getFile()파일명을 반환한다.
String getHost()호스트명을 반환한다.
String getPath()경로명을 반환한다.
int getPort()포트를 반환한다.
String getProtocol()프로토콜을 반환한다.
String getQuery()쿼리를 반환한다.
String getRef()참조(anchor)를 반환한다.
String getUserInfo()사용자정보를 반환한다.
URLConnection openConnection()URL과 연결된 URLConnection을 얻는다.
URLConnection openConnection(Proxy proxy)URL과 연결된 URLConnection을 얻는다.
InputStream openStream()URL과 연결된 URLConnection을 얻는다.
InputStream openStream()URL과 연결된 URLConnection의 InputStream을 얻는다.
boolean sameFile(URL other)두 URL이 서로 같은 것인지 알려준다.
void set(String protocal, String host, int port, String file, String ref)URL객체의 속성을 지정된 값으로 설정한다.
String toExternalForm()URL을 문자열로 변환하여 반환한다.
URI toURI()URL을 URI로 변환하여 반환한다.

URL 객체를 생성하는 방법

URL url = new URL("http://www.codechobo.com/sample/hello.html");
URL url = new URL("www.codechobo.com", "/sample/hello.html");
URL url = new URL("http", "www.codechobo.com", 80, "/sample/hello.html");

예제

import java.net.*;

class Ex16_2 {
    public static void main(String args[]) throws Exception {
        URL url = new URL("http://www.codehobo.com:80/sample/"
                + "hello.html?referer=codehobo#index1");
        System.out.println("url.getAuthority():" + url.getAuthority());
        System.out.println("url.getContent():" + url.getContent());
        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());
    }
}

-- result --
/Library/Java/JavaVirtualMachines/jdk-16.0.2.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=54477:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/seungjulee/eclipse-workspace/_ch2/bin Ex16_2
url.getAuthority():www.codehobo.com:80
url.getContent():sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@6e8cf4c6
url.getDefaultPort():80
url.getPort():80
url.getFile():/sample/hello.html?referer=codehobo
url.getHost():www.codehobo.com
url.getPath():/sample/hello.html
url.getProtocol():http
url.getQuery():referer=codehobo
url.getRef():index1
url.getUserInfo():null
url.toExternalForm():http://www.codehobo.com:80/sample/hello.html?referer=codehobo#index1
url.toURI():http://www.codehobo.com:80/sample/hello.html?referer=codehobo#index1

URLConnection 클래스

어플리케이션과 URL간의 통신연결을 나타내는 클래스의 최상위 클래스. 추상클래스이다.

진짜 여기 밑에 진짜 많은 메서드 엄청많음.

메서드설명
void addRequestProperty(String key, String value)지정된 키와 값을 RequestProperty에 추가한다.
기존에 같은 키가 있어도 값을 덮어쓰지 않는다.
void connect()URL에 지정된 자원에 대한 통신연결을 연다.
boolean getAllowUserInteraction()UserInteraction의 허용여부를 반환한다.
int getConnectTimeout()연결종료시간을 천분의 일초로 반환한다.
Object getContent()content객체를 반환한다.
Object getContent(Class[] classes)content객체를 반환한다.
String getContentEncoding()content의 인코딩을 반환한다.
int getContentLength()content의 크기를 반환한다.
String getContentType()content의 type을 반환한다.
long getDate()헤더(header)의 date필드의 값을 반환한다.
boolean getDefaultAllowUserInteraction()dafaultAllowUserInteraction의 값을 반환한다.
String getDefaultRequestProperty(String key)RequestProperty에서 지정된 키의 디폴트값을 얻는다.
boolean getDefaultUseCaches()useCache의 디폴트 값을 얻는다.
boolean getDoInput()doInput필드값을 얻는다.
boolean getDoOutput()doOutput필드값을 얻는다.
long getExpiration()자원(URL)의 만료일자를 얻는다.(천분의 일초단위)
FileNameMap getFileNameMap()FileNameMap(mimetable)을 반환한다.
String getHeaderField(int n)헤더의 n번째 필드를 읽어온다.
String getHeaderField(String name)헤더에서 지정된 이름의 필드를 읽어온다.
long getHeaderFieldDate(String name, long default)지정된 필드의 값을 날짜값으로 변환하여 반환한다.
필드값이 유효하지 않을 경우 default값을 반환한다.
int getHeaderFieldInt(String name, int default)지정된 필드의 값을 정수값으로 변환하여 반환한다.
필드값이 유효하지 않을 경우 default값을 반환한다.
String getHeaderFieldKey(int n)헤더의 n번째 필드를 읽어온다.
Map getHeaderFields()헤더의 모든 필드와 값이 저장된 Map을 반환한다.
long getIfModifiedSince()ifModifiedSince(변경여부)필드의 값을 반환한다.
InputStream getInputStream()URLConnection에서 InputStream을 반환한다.
long getLastModified()LastModified(최종변경일)필드의 값을 반환한다.
OutputStream getOutputStream()URLConnection에서 OutputStream을 반환한다.
Permission getPermission()Permission(허용권한)을 반환한다.
int getReadTimeout()읽기제한시간의 값을 반환한다.(천분의 일초)
Map getRequestProperties()RequestProperties에 저장된 (키, 값)을 Map으로 반환
String getRequestProperty(String key)RequestProperty에서 지정된 키의 값을 반환한다.
URL getURL()URLConnection의 URL을 반환한다.
boolean getUseCaches()캐쉬의 사용여부를 반환한다.
String guessContentTypeFromName(String fname)지정된 파일(fname)의 content-type을 추측하여 반환한다.
String guessContentTypeFromStream(InputStream is)지정된 입력스트림(is)의 content-type으 ㄹ추측하여 반환한다.
void setAllowUserInteraction(boolean allowuserinteraction)UserInteraction의 허용여부를 설정한다.
void setConnectTimeout(int timeout)연결종료시간을 설정한다.
void setContentHandlerFactory(ContentHandlerFactory fac)ContentHandlerFactory를 설정한다.
void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction)UserInteraction허용여부의 기본값을 설정한다.
void setDefaultRequestProperty(String key, String value)RequestProperty의 기본 키쌍(key-pair)을 설정한다.
void setDefaultUseCaches(boolean defaultusecaches)캐쉬 사용여부의 기본값을 설정한다.
void setDoInput(boolean doinput)DoInput필드의 값을 설정한다.
void setDoOutput(boolean dooutput)DoOutput필드의 값을 설정한다.
void setFileNameMap(FileNameMap map)FileNameMap을 설정한다.
void setIfModifiedSince(long ifmodifiedsince)ModifiedSince필드의 값을 설정한다.
void setReadTimeout(int timeout)읽기제한시간을 설정한다.(천분의 일초)
void setRequestProperty(String key, String value)RequestProperty에 (key, value)를 저장한다.
void setUseCaches(boolean usecaches)캐쉬의 사용여부를 설정한다.

이중에 하나라도 안쓰면 좀 억울할듯 합니다. 언젠간 사용하도록 합시다.

import java.net.*;

class Ex16_3 {
    public static void main(String args[]) {
//        String address = "https://www.codechobo.com/sample/hello.html";
        String address = "https://www.naver.com";
        try {
            URL url = new URL(address);
            URLConnection conn = url.openConnection();
            System.out.println("conn.toString():" + conn);
            System.out.print("getAllowUserInteraction():"
                    + conn.getAllowUserInteraction());
            System.out.println("\t\t\tgetConnectTimeout():" + conn.getConnectTimeout());
            System.out.println("getContent():" + conn.getContent());
            System.out.print("getContentEncoding():" + conn.getContentEncoding());
            System.out.println("\t\t\tgetContentLength():" + conn.getContentLength());
            System.out.print("getContentType():" + conn.getContentType());
            System.out.println("\tgetDate():" + conn.getDate());
            System.out.println("getDefaultAllowUserInteraction():"
                    + conn.getDefaultAllowUserInteraction());
            System.out.print("getDefaultUseCaches():" + conn.getDefaultUseCaches());
            System.out.println("\t\t\tgetDoInput():" + conn.getDoInput());
            System.out.print("getDoOutput():" + conn.getDoOutput());
            System.out.println("\t\t\t\tgetExpiration():" + conn.getExpiration());
            System.out.println("getHeaderFields():" + conn.getHeaderFields());
            System.out.print("getIfModifiedSince():" + conn.getIfModifiedSince());
            System.out.println("\t\t\t\tgetLastModified():" + conn.getLastModified());
            System.out.println("getReadTimeout():" + conn.getReadTimeout());
            System.out.println("getURL():" + conn.getURL());
            System.out.println("getUseCaches():" + conn.getUseCaches());
        } catch(Exception e) {e.printStackTrace();}
    }
}

--- result ---
/Library/Java/JavaVirtualMachines/jdk-16.0.2.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55172:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/seungjulee/eclipse-workspace/_ch2/bin Ex16_3
conn.toString():sun.net.www.protocol.https.DelegateHttpsURLConnection:https://www.naver.com
getAllowUserInteraction():false			getConnectTimeout():0
getContent():sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@769e7ee8
getContentEncoding():null			getContentLength():-1
getContentType():text/html; charset=UTF-8	getDate():1633882809000
getDefaultAllowUserInteraction():false
getDefaultUseCaches():true			getDoInput():true
getDoOutput():false				getExpiration():0
getHeaderFields():{Transfer-Encoding=[chunked], null=[HTTP/1.1 200 OK], Server=[NWS], Connection=[keep-alive], Pragma=[no-cache], P3P=[CP="CAO DSP CURa ADMa TAIa PSAa OUR LAW STP PHY ONL UNI PUR FIN COM NAV INT DEM STA PRE"], Date=[Sun, 10 Oct 2021 16:20:09 GMT], Referrer-Policy=[unsafe-url], X-Frame-Options=[DENY], Strict-Transport-Security=[max-age=63072000; includeSubdomains], Cache-Control=[no-cache, no-store, must-revalidate], Set-Cookie=[PM_CK_loc=08f2d0613dba6406ba63237a19665810bbafae9d5dc99374957c3536b5806be0; Expires=Mon, 11 Oct 2021 16:20:09 GMT; Path=/; HttpOnly], X-XSS-Protection=[1; mode=block], Content-Type=[text/html; charset=UTF-8]}
getIfModifiedSince():0				getLastModified():0
getReadTimeout():0
getURL():https://www.naver.com
getUseCaches():true

Process finished with exit code 0

예제2

import java.net.*;
import java.io.*;

public class Ex16_4 {
    public static void main(String args[]) {
        URL url = null;
        BufferedReader input = null;
        String address = "https://www.naver.com";
        String line = "";

        try {
            url = new URL(address);
            // url.openStream으로 URLConnection의 InputStream을 얻는다.
            input = new BufferedReader(new InputStreamReader(url.openStream()));

            while((line=input.readLine()) != null) {
                System.out.println(line);
            }
            input.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

예제3

import java.net.*;
import java.io.*;

public class Ex16_5 {
    public static void main(String args[]) {
        URL url = null;
        InputStream in = null;
        FileOutputStream out = null;
        String address = "https://www.naver.com";
//        String address = "https://www.youtube.com";

        int ch = 0;

        try {
            url = new URL(address);
            in = url.openStream();
            out = new FileOutputStream("javabasic_src.html");

            while((ch=in.read()) != -1) {
                out.write(ch);
            }
            in.close();
            out.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

소켓(socket) 프로그래밍

소켓 프로그래밍은 소켓을 이용한 통신 프로그래밍을 뜻한다.
소켓 : 프로세스간의 통신에 사용되는 양쪽 끝단(endpoint)

TCP와 UDP

전송계층에 있는 친구들이다.(transport layer)

항목TCPUDP
연결방식연결기반(connection-oriednted)
연결 후 통신(전화기)
1:1 통신방식
비연결기반(connectionless-oriented)
연결없이 통신(소포)
1:1, 1:n, n:n 통신방식
특징데이터의 경계를 구분안함(byte-stream)
신뢰성 있는 데이터 전송
전송순서 보장됨
수신여부 확인함
패킷을 관리할 필요가 없음
대신에 UDP보다 전송속도가 느림
데이터의 경계를 구분함.(datagram)
신뢰성 없는 데이터 전송
전송순서 바뀔 수 있음
수신여부 확인안함
패킷 관리해줘야댐
TCP보다 전송속도가 빠름
관련 클래스Socket
ServerSocket
DatagramSocket
DatagramPacket
MulticastSocket

TCP 소켓 프로그래밍

서버 프로그램과 클라이언트 프로그램간의 통신과정

  1. 서버 프로그램에서는 서버소켓을 사용해서 서버 컴퓨터의 특정 포트에서 클라이언트의 연결요청을 처리할 준비를 한다.
  2. 클라이언트 프로그램은 접속할 서버의 IP주소와 포트 정보를 가지고 소켓을 생성해서 서버에 연결을 요청한다.
  3. 서버소켓은 클라이언트의 연결요청을 받으면 서버에 새로운 소켓을 생성해서 클라이언트의 소켓과 연결되도록 한다.
  4. 이제 클라이언트의 소켓과 새로 생성된 서버의 소켓은 서버소켓과 관계없이 일대일 통신을 한다.

Socket과 ServerSocket

Socket
프로세스간의 통신을 담당, InputStream과 OutputStream을 가지고 있다.

ServerSocket
포트와 연결되어 외부의 연결요청을 기다리다가 연결요청이 들어오면 Socket을 생성해서 소켓과 소켓간의 통신이 이루어지도록 한다.

예제 16-6
예제 16-7

UDP 소켓 프로그래밍 - Client

TCP - Socket, ServerSocket
UDP - DatagramSocket, DatagramPacket

UDP는 연결지향이 아니라서 ServerSocket이 필요없다. 그래서 UDP통신에서 사용하는 소켓은 DatagramSocket이고 데이터를 gramPacket에 담아서 전송한다.

DatagramPacket을 전송하면 DatagraPacket에 지정된 주소의 DatagramSocket에 도착한다.

예제 16-8

post-custom-banner

0개의 댓글