[JAVA] chapter 16 네트워킹 - 1

WOOK JONG KIM·2022년 10월 7일

자바의 정석

목록 보기
25/25
post-thumbnail

ch16-1 네트워킹

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

java.net 패키지를 이용하면 네트워크 어플리케이션의 데이터 통신 부분 쉽게 작성 가능

ch16-2 클라이언트 & 서버

서버 : 서비스를 제공하는 컴퓨터(다수 클라이언트 대상)

클라이언트 : 서비스를 사용하는 컴퓨터

서비스 : 클라이언트로부터 요청받은 작업을 처리하여 결과를 제공하는 것

서버가 서비스를 제공하기 위해서는 서버 프로그램이 있어야 하고 클라이언트가 서비스를 제공받기 위해서는 서버 프로그램을 연결할 클라이언트 프로그램이 있어야 함

ex) 웹 서버에 접속해서 정보를 얻기위해 -> 웹브라우저(클라이언트 프로그램)
FTP 서버에 접속해서 파일을 전송받기 위해 -> FTP 클라이언트 프로그램

네트워크 구성 시 전용 서버를 두는 것 -> 서버 기반 모델

전용 서버 없이 각 클라이언트가 서버역할 동시에 수행하는 것 -> P2P 모델

ch16-3 Ip주소

컴퓨터를 구별하는데 사용하는 고유한 값(4byte 정수로 구성)

a.b.c.d 형태로 구성 (a,b,c,d는 부호없는 1byte, 0~255)

네트워크 주소 + 호스트 주소로 구성
->4byte 중 각각 몇 bit를 차지하는 지는 네트워크 구성 방법에 따라 다름

네트워크 주소가 같다 -> 두 호스트가 같은 네트워크에 포함되어 있다는 것

ch16-4 네트워크 및 호스트 주소

Ip주소와 서브넷 마스크를 &연산 하면 네트워크 주소만을 뽑아 낼 수 있다

네트워크 주소가 차지하는 자리수가 많을수록 호스트 주소 범위 줄어들어 네트워크 범위 작아짐

위 경우 호스트 주소 자리 -> 8자리(256개 호스트) -> 0 : 자기 자신 255: 브로드 캐스트 주소 -> 총 254개의 호스트 개수 사용 가능

ch16-5,6 InetAddress 클래스

Ip주소를 다루기 위한 클래스

package ch16;

import java.net.*;
import java.rmi.UnknownHostException;
import java.util.*;

public class Ex16_1 {

	public static void main(String[] args) throws java.net.UnknownHostException {
		InetAddress ip = null;
		InetAddress[] ipArr = null;
		
		
			// 도메인 명을 통해 Ip주소를 얻음
			ip = InetAddress.getByName("www.naver.com");
			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]) + ".";
			System.out.println("getAddress() + 256 : " + result);
			System.out.println();

		

			ip = InetAddress.getLocalHost();
			System.out.println("getHostName():" + ip.getHostName());
			System.out.println("getHostAddress(): " + ip.getHostAddress());
			System.out.println();

		

			ipArr = InetAddress.getAllByName("www.naver.com");
			
			for(int i=0; i < ipArr.length; i++)
				System.out.println("ipArr["+i+"] :" + ipArr[i]);
	
	}

}
getHostName():www.naver.com
getHostaddress() 223.130.200.107
toString():www.naver.com/223.130.200.107
getAddress() : [-33, -126, -56, 107]
getAddress() + 256 : 223.130.200.107.

getHostName():gim-ugjong-ui-MacBookAir.local
getHostAddress(): 127.0.0.1

ipArr[0] :www.naver.com/223.130.200.107
ipArr[1] :www.naver.com/223.130.195.200

ch16-7~13 URL(Uniform Resource Locator)

인터넷에 존재하는 여러 서버들이 제공하는 자원에 접근할 수 있는 주소

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

http://www.codechobo.com:80/sample/hello.html?referer=codechobo#index1

프로토콜 : 자원에 접근하기 위해 서버와 통신하는데 사용하는 통신규약(http)

호스트명 : 자원을 제공하는 서버의 이름(www.codechobo.com)

포트번호 : 통신에 사용되는 서버의 포트번호(80)

경로명 : 접근하려는 자원이 저장된 서버상의 위치(/sample/)

파일명 : 접근하려는 자원의 이름(hello.html)

쿼리: URL에서 ?이후의 부분(referer=codechobo)

참조 : URL에서 # 이후의 부분(index1)

포트 번호 생략시 http프로토콜에서 사용하는 80번 포트라고 간주

package ch16;

import java.net.*;

public class ex16_2 {

	public static void main(String[] args) throws Exception {
		URL url = new URL("http://www.codechobo.com:80/sample/"
					+ "hello.html?referer=codechobo#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());

	}

}

URLConnection 클래스

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

연결하고자 하는 자원에 접근하고 읽고 쓰기를 할 수 있다

HttpURLConnectionJarURLConnection은 URLConnection을 상속받아 구현한 클래스로 URL의 프로토콜이 http 프로토콜이라면 openConnection( )은 HttpURLconnection을 반환


ch16-14~20 소켓 프로그래밍

소켓 : 프로세스간의 통신에 사용하는 양쪽 끝단(endpoint), 프로세스간 통신을 위해서 필요

java.net 패키지를 통해 소켓 프로그래밍을 지원하며 통신에 사용하는 프로토콜에 따라 다른 종류의 소켓을 구현하여 제공

TCP/IP -> 이기종 시스템간의 통신을 위한 표준 프로토콜 집합

TCP,UDP는 TCP/IP프로토콜에 포함되어 있으며 OSI7계층중 전송 계층

  • TCP는 데이터를 전송하기 전에 먼저 상대편과 연결을 한 후 데이터를 전송하며 잘 전송되었는지 확인하고 실패했다면 데이터를 재전송한다. 신뢰 있는 데이터의 전송이 요구되는 통신에 적합하다. (ex - 파일전송), 일종의 통화

  • UDP는 상대편과 연결하지 않고 데이터를 전송한다. 데이터를 전송하지만 데이터가 바르게 수신되었는지 확인하지 않기 때문에 데이터가 전송되었는지 확인할 길이 없다. (데이터를 보낸 순서대로 수신한다는 보장x), 일종의 소포
    -> 게임이나 동영상 같이 데이터가 중간에 손실되더라도 빠른 전송이 필요할 때 적합하다.

TCP 소켓 프로그래밍

클라이언트와 서버간 1:1 통신

서버 프로그램이 먼저 실행되어 클라이언트 프로그램의 연결 요청을 기다리고 있어야 한다

서버 소켓 : 포트와 결합되어 포트를 통해 원격 사용자의 연결요청을 기다리다가 연결 요청이 올 때마다 새로운 소켓을 생성하여 상대편 소켓과 통신할 수 있도록 연결 (일종의 전화 교환기)

일반적인 여러개의 소켓은 하나의 포트를 공유해서 사용할 수 있지만 , 서버 소켓은 포트 독점

포트 : 호스트가 외부와 통신하기 위해 사용 하는 통로

1. 서버 프로그램에서는 서버 소켓을 사용해서 서버 컴퓨터의 특정 포트에서 클라이언트의 연결요청을 처리할 준비

2. 클라이언트 프로그램은 접속할 서버의 IP주소와 포트 정보를 가지고 소켓을 생성해서 서버에 연결을 요청

3. 서버소켓은 클라이언트의 연결요청을 받으면 서버에 새로운 소켓을 생성해서 클라이언트의 소켓과 연결되도록 한다

4. 이제 클라이언트의 소켓과 새로 생성된 서버의 소켓은 서버소켓과 관계없이 일대일 통신

즉 서버 소켓은 소켓간의 연결만 처리하고 실제 데이터는 소켓 끼리 주고 받음
-> 주고 받는 연결통로 : 입출력 스트림

교차 연결을 통해 한 소켓에서 출력스트림으로 데이터를 보내면 상대편 소켓에서 입력 스트림으로 받음

package ch16;

import java.net.*;
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;

public class TcpIPServer {

	public static void main(String[] args) {
		ServerSocket serverSocket = null;
		
		try {
			// 서버 소켓을 생성하여 7777번 포트와 bind 시킨다.
			serverSocket = new ServerSocket(7777);
			System.out.println(getTime()+"서버가 준비되었습니다.");
		} catch(IOException e) { e.printStackTrace();}
		
		while(true) {
			try {
				System.out.println(getTime() + "연결 요청을 기다립니다. ");
				// 서버  소켓은 클라이언트의 요청이 올때까지 실행을 멈추고 기다린다.
				// 클라이언트의 연결요청이 오면 클라이언트 소켓과 통신할 새로운 소켓을 생성한다. 
				
				Socket socket = serverSocket.accept();
				System.out.println(getTime() + socket.getInetAddress() +"로 부터 연결 요청이 들어왔습니다.");
				
				// 소켓의 출력스트림을 얻는다. 
				OutputStream out = socket.getOutputStream();
				DataOutputStream dos = new DataOutputStream(out);
				
				// 원격 소켓(클라이언트의 소켓) 에 데이터를 보낸다.
				dos.writeUTF("[Notice] Test Message1 from Server.");
				System.out.println(getTime() + "데이터를 전송하였습니다. ");
				
				//스트림과 소켓을 닫아준다. 
				dos.close();
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}
	
	// 현재 시간을 문자열로 변환하는 정수
	static String getTime() {
		SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
		return f.format(new Date());
	}

}

예제 실행 시 서버소켓이 7777번 포트에서 클라이언트에서 요청 기다림

클라이언트 프로그램이 서버에 연결 요청 시 서버 소켓이 새로운 소켓 생성하여 원격 소켓과 연결

새로 생성된 소켓은 데이터를 원격 소켓에 전송하고 연결 종료

package ch16;

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

public class TcpIpCilent {

	public static void main(String[] args) {
		try {
			String serverIp = "127.0.0.1";
			
			System.out.println("서버에 연결 중입니다. 서버IP :" + serverIp);
			// 소켓을 생성하여 연결 요청 , 생성시 자동으로 요
			Socket socket = new Socket(serverIp, 7777);
			
			// 소켓의 입력 스트림 얻음
			InputStream in = socket.getInputStream();
			DataInputStream dis = new DataInputStream(in);
			
			// 소켓으로 부터 받은 데이터를 출력
			System.out.println("서버로부터 받은 메세지: " + dis.readUTF());
			System.out.println("연결을 종료합니다. ");
			
			dis.close();
			socket.close();
			System.out.println("연결이 종료되었습니다.");
		} catch(ConnectException ce) {
			ce.printStackTrace();
		} catch(IOException ie) {
			ie.printStackTrace();
		} catch(Exception e) {
			e.printStackTrace();
		}

	}

}

UDP 소켓 프로그래밍

UDP는 연결 지향적인 프로토콜이 아니라서 ServerSocket 필요 X
-> DatagramSocketDatagramPacket 사용

데이터를 DatagramPacket에 담아서 전송
-> 헤더(패킷을 수신할 호스트의 정보)와 데이터로 구성

package ch16;

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

public class UdpClient {
	
	public void start() throws IOException, UnknownHostException{
		DatagramSocket datagramSocket = new DatagramSocket();
		InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
		
		// 데이터가 저장될 공간으로 byte 배열 생성
		byte[] msg = new byte[100];
		
		DatagramPacket outPacket = new DatagramPacket(msg,1,serverAddress, 7777);
		DatagramPacket inPacket = new DatagramPacket(msg,msg.length);
		
		datagramSocket.send(outPacket); // packet 전송
		datagramSocket.receive(inPacket); // packet 수신
		
		System.out.println("current server time:"
				+ new String(inPacket.getData()));
		datagramSocket.close();
	} 

	public static void main(String[] args) {
		try {
			new UdpClient().start();
		} catch(Exception e) {
			e.printStackTrace();
		}

	}

}
package ch16;

import java.net.*;
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;

public class UdpServer {
	public void start() throws IOException{
		// 포트 7777번 사용하는 소켓을 생성한다.
		DatagramSocket socket = new DatagramSocket(7777);
		DatagramPacket inPacket, outPacket;
		
		byte[] inMsg = new byte[10];
		byte[] outMsg;
		
		while(true) {
			// 데이터 수신하기 위한 패킷 생성
			inPacket = new DatagramPacket(inMsg, inMsg.length);
			socket.receive(inPacket); // 패킷을 통해 데이터 수신
			
			// 수신할 패킷으로 부터 cilent의 IP주소와 Port를 얻는다
			InetAddress address = inPacket.getAddress();
			int port = inPacket.getPort();
			
			// 서버의 현재 시간을 시분초 형태[hh:mm:ss] 로 반환
			SimpleDateFormat sdf = new SimpleDateFormat("[hh:mm:ss]");
			String time = sdf.format(new Date());
			outMsg = time.getBytes(); // time을 byte배열로 반환
			
			// 패킷을 생성해서 client 에게 전송
			outPacket = new DatagramPacket(outMsg, outMsg.length, address, port);
			socket.send(outPacket);
		}
	}

	public static void main(String[] args) {
		try {
			new UdpServer().start(); // UDP 서버 실
		} catch(IOException e) {
			e.printStackTrace();
		}

	}

}
profile
Journey for Backend Developer

0개의 댓글