[Network] 네트워크

포키·2023년 3월 20일
0

국비과정

목록 보기
45/73
  • 네트워크에서 쓰레드 많이 나옴
  • 앞에서 배운거 싹 다 나옴

네트워크

네트워크란? 참고

  • 네트워크란 컴퓨터간 연결, 통신하는 행위
  • 네트워크망 = 컴퓨터간 연결하는 망

ip(internet protocol)

  • 디바이스 식별자
    네트워크망에서 원하는 디바이스(PC 등)을 찾게 해줌
  • ip의 확장
    기존 ipv4 사용 -> ipv6로 변경

port

  • 프로세스 식별자
    ip로 기기를 찾는다고 끝이 아님. 실제로 연결되어야 하는 것은 프로세스와 프로세스.
  • 10000번까지는 이미 약속된 port (사용할 곳이 정해져있음),
    따라서 우리가 포트를 사용할 때는 10000번 이후를 사용해야 함.
  • c.f. pid(Process Id)

DNS (Domain Name Server)

  • 도메인 주소를 넣으면 ip를 반환함. 컴퓨터는 받은 ip를 이용하여 해당 주소에 접근함.
  • 도메인 주소를 사용하면 ip 주소가 바뀌어도 사용자는 기존 도메인 주소를 통해 문제없이 접근할 수 있음.
  • 웹은 아무것도 넣지 않으면 기본 port : 80으로 접근함. (= 기본 웹 서버의 포트번호)
  • HTML -> XHTML, HTML5
    당시 대부분 XHTML(스트리밍 : 플래시 지원)로 넘어감 (웹브라우저 게임, 유튜브 등에서도 사용)
    아이폰의 등장(플래시 지원 안함) -> XHTML 사양되고 HTML5가 표준이 됨.
  • HTML (Hypertext Markup Language)
    일반적 선형 문서(text)를 넘어선 비선형 문서(hypertext)
    아날로그에서 디지털로의 전환을 선형에서 비선형으로의 전환으로 설명하기도 한다.

프로토콜Protocol, 통신규약

  • 클라이언트 - 요청(request) -> <- 응답(response) - 서버
  • 클라이언트가 요청할 수 있는 범위, 서버가 응답할 수 있는 범위를 미리 정하여두는 것.
    ex) http, ftp 등
  • 간단히 말하면 중국집에 요청하고 응답받을 수 있는 것 = 중국집 메뉴라고 미리 정해놓는 것!
  • 프로토콜은 국제 표준을 정하는 단체에서 정한다.
    ex) w3c(월드 와이드 웹을 위한 표준을 개발), IEEE(전기 전자에 대한 산업 표준을 개발)
  • 네트워크에서 request 하는 것은 자바에서 메서드를 사용하던 것과 크게 다르지 않음
    ex) search(String keyword) || 프로토콜 :\\URL ? query
    URL이 메서드 이름(무엇을 하는가)
    query가 패러미터(기능을 위해 어떤 정보가 필요한가)
    이 전체를 자바에서는 method, 네트워크에서는 request
  • 예시) TCP, UDP

TCP

  • 연결 지향 (like 전화. 언제나 받는 상대가 필요함. 누구한테 보냈고 잘 받았는지 확인 필수)
  • 웹 방식
  • 신뢰성 보장 (상대방 확인 필수)

UDP

  • 비연결 지향 (like 편지. 방송. 상대가 잘 받았는지 아닌지 모름.)
  • 토렌트 방식
  • 속도 보장 (상대방 확인 x)

OSI 7계층

  • 자바에서 소켓 사용하면 자동으로 맞게 보내고 받아짐
  • OSI 7계층 참고
  • 컴퓨터상의 표준
    표준이 정해져있지만 지켜지지 않는 분야도 있다 (ex) 자바스크립트, sql)
    이유 : 경쟁 과정에서 벗어남
    그러나 표준을 기반으로 발전했기 때문에, 표준을 이해한다면 발전된 프로그램도 이해하기 수월함
    그래서 우리는 MySQL으로 공부할 것

자바스크립트 - 제이쿼리 - 크로스브라우징(어떤 브라우저에서나 접근 가능)을 편하게 함.

예제 코드 - 도메인에서 ip 뽑아내기

public class NSLookup {
	public static void main(String[] args) {
		String domain = JOptionPane.showInputDialog("도메인을 입력하시오");
		// IP 나타내는 객체
		// 배열 객체 <- 도메인 하나당 나타내는 ip가 여러개기 때문
		InetAddress[] inetaddr = null;
		try {
			inetaddr = InetAddress.getAllByName(domain);
		} catch(UnknownHostException e) {
			e.printStackTrace();
		}
		for(int i = 0; i < inetaddr.length; i++) {
			System.out.println(inetaddr[i].getHostName());
			System.out.println(inetaddr[i].getHostAddress());
			System.out.println(inetaddr[i].toString());
			System.out.println("-----------------------");
		}
	} //main
}

소켓(Socket)

  • 소켓이란? 전화기같은 것. 상대와 정보를 주고받는 창구.
    서버와 클라이언트의 소통은 소켓을 통해 이루어진다.
    통신은 소켓이 하고, 서버, 클라이언트는 각자 소켓을 상대방으로 생각하고 read & write 한다.
  • Socket 참고
  • Socket 통신 과정 참고

  • 서버 소켓 : 서버를 열고 클라이언트의 접촉을 기다리는 역할 (접속 대기)
  • 클라이언트 소켓 :

(??? 서버 만들고 클라이언트 만들고 할 줄 알면 대단한거)

예시 코드 - 서버-클라이언트 (일대일) 통신

  • 클라이언트 코드
public class EchoClient {
	public static void main(String[] args) {
		Socket sock = null;

		OutputStream out = null;
		OutputStreamWriter osw = null;
		PrintWriter pw = null;

		InputStream in = null;
		InputStreamReader isr = null;
		BufferedReader br = null;

		BufferedReader keyboard = null;
		InputStreamReader keyIsr = null;

		try {
			// 소켓 생성 : 접속했음
			// server 정보 (디바이스 식별자, 포트 식별자)
			sock = new Socket("127.0.0.1", 10001);
			
			// 키보드 io 스트림
			keyIsr = new InputStreamReader(System.in);
			keyboard = new BufferedReader(keyIsr);

			out = sock.getOutputStream();	// 소켓에 쓰기
			in = sock.getInputStream();		// 소켓을 읽기
			
			osw = new OutputStreamWriter(out);
			pw = new PrintWriter(osw);

			isr = new InputStreamReader(in);
			br = new BufferedReader(isr);
			String line = null;
			// 키보드입력 대기 : 읽을 게 생길 때까지 멈춤
			while ((line = keyboard.readLine()) != null) {
				if (line.equals("quit")) {
					break;
				}
				pw.println(line);	// 키보드로 입력받은 line을 서버(소켓)에 쓰기
				pw.flush();
				// 서버로부터 전송 대기
				String echo = br.readLine();
				System.out.println("서버로부터 전달받은 문자열 : " + echo);
			}
			pw.close();
			br.close();
			sock.close();
		} catch (Exception e) {
			System.out.println(e);
		} finally {
			try {
				keyboard.close();
			} catch (Exception e) {	}
			try {
				keyIsr.close();
			} catch (Exception e) {	}
			try {
				br.close();
			} catch (Exception e) {	}
			try {
				isr.close();
			} catch (Exception e) {	}
			try {
				in.close();
			} catch (Exception e) {	}
			try {
				pw.close();
			} catch (Exception e) {	}
			try {
				osw.close();
			} catch (Exception e) {	}
			try {
				out.close();
			} catch (Exception e) {	}
			try {
				sock.close();
			} catch (Exception e) {	}
		}
	}	// main
}
  • ip 중 127로 시작하는 ip는 내부ip
    127.0.0.1은 '나'를 가리키는 ip - 지금 나에게 접속한 것
    (물리적으로 같지만 논리적으로 다른 것으로 인식됨)
  • 클라이언트가 잘못된 주소로 연결 시도할 경우 : 거절 -> ConnectException 발생
  • 서버 코드
public class EchoServer {
	public static void main(String[] args) {
		Socket sock = null;
		
		OutputStream out = null;
		OutputStreamWriter osw = null;
		PrintWriter pw = null;
		
		InputStream in = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		
		try {
			ServerSocket server = new ServerSocket(10001);
			System.out.println("접속을 기다립니다.");
			// 1
			// Client 정보가 담긴 소켓
			sock = server.accept();	// return : Socket 객체
			// 멈춤 -> blocked
			// 서버 측에서는 프로그램이 멈춤 - 누군가 접속할 때까지
			// 소켓이란? 전화기같은 것
			InetAddress inetaddr = sock.getInetAddress();
			System.out.println(inetaddr.getHostAddress() + "로부터 접속하였습니다.");
			
			out = sock.getOutputStream();	// 소켓에 쓰기
			in = sock.getInputStream();		// 소켓을 읽기
			
			osw = new OutputStreamWriter(out);
			pw = new PrintWriter(osw);
			
			isr = new InputStreamReader(in);
			br = new BufferedReader(isr);
			String line = null;
			// 소켓입력 대기 : 읽을 게 생길 때까지 멈춤
			while((line = br.readLine()) != null) {
				System.out.println("클라이언트로부터 전송받은 문자열 : " + line);
				pw.println(line);
				pw.flush();
			}
			System.out.println(line);
		} catch(Exception e) {
			System.out.println(e);
		} finally {
			try {
				br.close();
			} catch(Exception e) {}
			try {
				isr.close();
			} catch(Exception e) {}
			try {
				in.close();
			}catch (Exception e) {}
			try {
				pw.close();
			}catch(Exception e) {}
			try {
				osw.close();
			}catch(Exception e) {}
			try {
				out.close();
			}catch(Exception e) {}
			try {
				sock.close();
			} catch(Exception e) {}
		}
	}	// main
}

예시 코드 - 서버-클라이언트 일대다 통신

  • 그냥 해봄
  • 다수의 클라이언트의 접속을 받기 위해서는
  1. 클라이언트의 접속 대기 (server.accept())
  2. 클라이언트와 통신 (받은 소켓의 InStream, OutStreamread(), write() 수행)
  • 서버 코드
import java.util.List;
import java.util.Vector;
import java.util.Iterator;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.net.Socket;

public class EchoServer {
	static List<Socket> activeSocks;

	public static void main(String[] args) {
		activeSocks = new Vector<Socket>();

		try {
			ServerSocket server = new ServerSocket(10001);
			System.out.println("접속을 기다립니다.");

			CheckThread t2 = new CheckThread(activeSocks);
			t2.start();
			
			while(true) {
				Socket sock = server.accept();
				activeSocks.add(sock);

				synchronized(activeSocks) {
					SocketThread t1 = new SocketThread(activeSocks, sock);
					t1.start();
				}
			}
		} catch(Exception e) {
			System.out.println(e);
		}
	}	// main
}
class CheckThread extends Thread {
	private List<Socket> activeSocks;

	public CheckThread(List<Socket> activeSocks) {
		this.activeSocks = activeSocks;
	}

	@Override
	public void run() {
		InputStream is = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		OutputStream os = null;
		OutputStreamWriter osw = null;
		PrintWriter pw = null;

		try {
			is = System.in;
			isr = new InputStreamReader(is);
			br = new BufferedReader(isr);
			
			while(br.readLine().equals("1")){
				synchronized(activeSocks) {
					Iterator<Socket> itr = activeSocks.iterator();
					while(itr.hasNext()) {
						try {
							os = itr.next().getOutputStream();
							osw = new OutputStreamWriter(os);
							pw = new PrintWriter(osw);

							pw.println("연결 중인 클라이언트 수 : " + activeSocks.size());
							pw.flush();
						} catch(Exception e) {
							e.printStackTrace();
						}
					}
				}
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			MyUtils.closeAll(br, isr, is);
		}
	}
}
class SocketThread extends Thread {
	private List<Socket> activeSocks;
	private Socket sock;
	public SocketThread(List<Socket> activeSocks, Socket sock) {
		this.activeSocks = activeSocks;
		this.sock = sock;
	}
	@Override
	public void run() {
		OutputStream out = null;
		OutputStreamWriter osw = null;
		PrintWriter pw = null;
		InputStream in = null;
		InputStreamReader isr = null;
		BufferedReader br = null;

		try {
			InetAddress inetaddr = sock.getInetAddress();
			System.out.println(inetaddr.getHostAddress() + "로부터 접속하였습니다.");
			
			out = sock.getOutputStream();	// 소켓에 쓰기
			osw = new OutputStreamWriter(out);
			pw = new PrintWriter(osw);
			
			in = sock.getInputStream();		// 소켓을 읽기
			isr = new InputStreamReader(in);
			br = new BufferedReader(isr);

			String line = null;
			// 소켓입력 대기 : 읽을 게 생길 때까지 멈춤
			while((line = br.readLine()) != null) {
				System.out.println("클라이언트로부터 전송받은 문자열 : " + line);
				pw.println(line);
				pw.flush();
			}
			System.out.println(line);
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			MyUtils.closeAll(br, isr, in, pw, osw, out, sock);
			activeSocks.remove(sock);
		}
	}
}
  • 클라이언트 코드
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

public class EchoClient {
	static Socket sock;
	public static void main(String[] args) {
		OutputStream out = null;
		OutputStreamWriter osw = null;
		PrintWriter pw = null;
		
		InputStream in = null;
		InputStreamReader isr = null;
		BufferedReader br = null;

		BufferedReader keyboard = null;
		InputStreamReader keyIsr = null;
		
		// 필요한 일
		// 1. 키보드를 통해 유저가 할 말을 입력받음 (대기)
		// 2. 소켓을 통해 서버에서 연락을 받음 (대기)
		try {
			sock = new Socket("127.0.0.1", 10001);
			
			// 키보드 io 스트림
			keyIsr = new InputStreamReader(System.in);
			keyboard = new BufferedReader(keyIsr);

			out = sock.getOutputStream();	// 소켓에 쓰기
			in = sock.getInputStream();	// 소켓을 읽기
			
			osw = new OutputStreamWriter(out);
			pw = new PrintWriter(osw);

			isr = new InputStreamReader(in);
			br = new BufferedReader(isr);
			String line = null;

			ReceiveThread waitThread = new ReceiveThread(br);
			waitThread.start();

			// 키보드입력 대기 : 읽을 게 생길 때까지 멈춤
			while ((line = keyboard.readLine()) != null) {
				if (line.equals("quit")) {
					break;
				}
				pw.println(line);	// 키보드로 입력받은 line을 서버(소켓)에 쓰기
				pw.flush();
				// 서버로부터 전송 대기
				//String echo = br.readLine();
				//System.out.println("서버로부터 전달받은 문자열 : " + echo);
			}
			pw.close();
			br.close();
			sock.close();
		} catch (Exception e) {
			System.out.println(e);
		} finally {
			MyUtils.closeAll(keyboard, keyIsr, br, isr, in, pw, osw, out, sock);
		}
	}	// main
}
class ReceiveThread extends Thread {
	private BufferedReader br;
	private String inform;
	
	public ReceiveThread(BufferedReader br) {
		this.br = br;
	}
	@Override
	public void run() {
		try {
//			in = sock.getInputStream();
//			isr = new InputStreamReader(in);
//			br = new BufferedReader(isr);

			while((inform = br.readLine()) != null) {
				System.out.println("서버로부터 전달받은 문자열 : " + inform);
			}
		} catch(Exception e) {
			e.printStackTrace();
		} // finally {
//			MyUtils.closeAll(br, isr, in);
//		}
	}
}
  • 소켓 꼭 닫아주기

예제 코드 - 채팅 기능 구현

profile
welcome

0개의 댓글