네트워크 Socket

박철진·2021년 6월 29일
0

guarded suspension

  1. 목적 코드가 어떤 것인가? → getRequest() 같은 경우 목적은 return queue.remove(); 이다

  2. 가도 조건이 어떤 것인가? → synchronized while(가드조건) { wait(); } 목적코드;

  3. guarded suspension 패턴

  4. guaded Object(LinkedList<Request>();)의 상태변화를 해야하는 코드가 반드시 존재해야한다.(stateChanging Method)

[자바] Guarded-Suspension 패턴


※위에 내용 정리※

  1. guarded object : queue → private final Queue<Request> queue = new LinkedList<Request>();

  2. guarded method : getRequest()

    2.1 목적코드 : queue.remove();

    2.2 가드조건 : queue.peek() == null → wait()

    2.3 synchronized method() { while(가드조건) { wait() } 목적코드; }

  3. stateChanging method : putRequest() → guarded object의 상태 변화

    3.1 synchronized method() { guarded object의 상태 변화코드; notifyAll(); }


LinkedBlockingQueue<>()

take(), put() → 동기화 시켜주고 wait() 까지 지원해준다. 꺼낼게 없으면 못꺼내고 꺼낼게 들어오면 꺼내는 걸 구현할때 사용한다.


네트워크

통신이 가능한 디바이스(인터넷)

  • client(클라이언트) : 요청하는 쪽
  • server(서버) : 응답해주는 쪽

  • IP : 네트워크 상에서 장비를 식별하는 물리적 식별자이다. (인터넷 프로토콜), 장비 식별자
    • 프로토콜 : 어떤식으로 요청하면은 어떤식으로 대답해주는거다. 중국집에서 김밥을 시켜먹을 수 없듯이.
  • port : 장비 안에 동작하는 수많은 프로그램들이 있는데 어떤 프로그램이랑 연결할건지 결정하는 프로세스 식별자이고 논리적 식별자이다. 0 ~ 10000 번호까지는 약속된 port번호가 지정되 있어서 10000번 이상 번호로 port번호를 결정한다. 같은 port번호끼리는 충돌이 일어난다.
  • OSI 7 Layers : 각 단계마다 헤더가 붙는데 통신 내용에 검증 때문에 붙는다. 총 7개의 헤더가 붙고 헤더를 전기적 신호로 바꿔서 상대방 컴퓨터에게 전달하면서 다시 역순으로 헤더가 제거된다. 마지막으로 DATA만 남게 된다.

TCP

  • 연결형 통신 방식
  • 인터넷
  • 신뢰성 있는 데이터 보장
  • 전화로 예를 들면 상대방이 전화를 받아야 통화가 가능하며, 서로 주고 받는 메세지가 있다. 상대방이 내가 전달하는 메세지를 받았다 라고 확인이 가능하다.
  • 웹은 TCP 방식

UDP

  • 비 연결형 통신 방식
  • 송수신 신호 확인 절차 없음
  • 안정성이 낮고 속도에서 이득
  • 편지로 예를 들면 상대방이 편지를 받았는지 안받았는지 모르며 보낸 편지가 도착하는 날짜도 달라진다.

주소창에 도메인 이름(naver.com)을 넣으면 DNS(Domain name server)로 이동한다. DNS 안 목록에 있는 도메인 이름의 IP 주소를 돌려주고 Server는 돌려받은 IP주소로 다시 요청한다.


NSLookUp

public class NSLookUp {
	public static void main(String[] args) {
		String domain = JOptionPane.showInputDialog(
			"도메인을 입력하시오"
		);
		// 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
}
  • inetaddr = InetAddress.getAllByName(domain);
  • getHostName() : 도메인 이름
  • getHostAddress() : 아이피 번호
  • toString() : 호스트 네임 / 호스트 어드레스
  • 복수개의 IP로 구성되어 있다보니깐 배열 형태로 돌려준다
  • 도메인주소.com:80 → 80번 port로 연결한다. 웹사이이트들은 80번 포트를 쓰기로 약속이 되어있다.

EchoClient / EchoServer

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("접속을 기다립니다.");
			
			sock = server.accept();
			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
}
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 {
			sock = new Socket("127.0.0.1", 10001);
			
			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);
				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
}

서버 먼저 실행하고 클라이언트 실행하기

실행 결과

ServerSocket : 포트 번호로 접속 가능하다. 생성자에 10001은 포트 번호

server.accept() : 서버 소켓에 accept되면서 클라이언트가 접속할때까지 블로킹 상태가 된다.(Not Runnable 상태)

new Socket("127.0.0.1", 10001); : new Socket(ip, port);

  • 전화기는 내가 통화하고자는 하는 상대방을 나타낸다. 전화번호를 누르고 통화 버튼을 누르면 전화가 되지만 어떻게 작동하는지 모른다. 전화번호의 역할은 상대방의 장비를 찾는다. → socket 내가 통신하고자 하는 상대방을 역할이다. 전화기를 통해서 말을 전하고 상대방을 대신하는 것처럼.
  • OSI 7계층에서 일들을 Socket이 알아서 해준다.
  • Socket 생성됬다 = 접속했다. Server Socket이 appept 해야 접속이 가능하다. 크랄이언트와 서버에서 소켓을 서로 만들어줘야 접속이 가능하다.
  • 서버에서 getInetAddress() 뽑아냈다는건 클라이언트에 IP 주소를 가져온다.
  • while( (line = br.readLine()) != null ) 읽을게 있을때까지 readLine()에서 블로킹 된다.
  • 양쪽이 스트림이 완성되어 있는 상태에서 readLine() 에서 멈춰있다. 키보드로 입력하면 서버의 readline으로 line이 출력이 되고 클라이언트에 readline으로 넘어가고 콘솔창에 출력되고 난 다음 키보드로에서 대기한다.

  • out → osw → pw / in → isr → br / soket 순으로 만들어지기 때문에 역순으로 close() 해준다.

Client

  1. in : socket에서 나오는건 뽑아낸다는 말이기 때문에 방향성을 socket에서 나오는 방향이다.
  2. isr : byte를 char로 읽을 수 있게 해준다.
  3. br : readLine은 char로 읽어들인다.
  4. echo(String) :
    • System.out :
    • console :
  • out : 소켓에서 뽑아낸 아웃풋스트림은 소켓에 쓰는 역할.
  • osw : PrintWriter의 char를 getOutputStream byte로 읽을 수 있게 바꿔준다
  • pw : char 연산.
  • line(String) : keyborad에서 뽑아낸다.
    • System.in : 키보드에서 읽어낸다
    • keyIsr : InputStreamReader(System.in);
    • keyborad : BufferedReader(keyIsr); readLine() 발생
  • 조건문에서 처음 블로킹이 생긴다. 읽을게 생기면 line을 만들어내고 println하고 out까지 진행한다. → br String echo = br.readLine();에서 대기한다.
  • 이 코드에서 중요한건 어디에서 멈추냐이다.

Server

  • 한바퀴 돌고 br에 br.readLine(); 에서 대기한다.

echo란 메아리다.

  • echo 서버란, 클라이언트가 전송해 주는 데이터를 그대로 되돌려 전송해 주는 기능의 서버를 의미한다.
  • 클라이언트가 서버로 데이터를 전송하면 서버는 그 데이터를 받았다가 그대로 다시 되돌려 보내준다.
profile
개발자를 위해 기록하는 습관

0개의 댓글

관련 채용 정보