[자바 소켓통신] 87. 소켓통신

김건우's avatar
Feb 21, 2025
[자바 소켓통신] 87. 소켓통신
20-1. 소켓통신 숙제
20-1. 소켓통신 숙제
💡
TCP/IP 기반 네트워크 통신에서 데이터 송수신의 마지막 접점
서버 - 클라이언트 간 데이터를 주고받는 양방향 연결 지향성 통신
컴퓨터를 식별하기 위한 IP 주소 / 컴퓨터 내에서 현재 통신에 사용되는 응용프로그램을 식별하기 위한 포트번호가 사용된다
💡
서버는 데이터를 제공하는 쪽
클라이언트는 데이터를 요청하여 제공받는 쪽

소켓 통신 종류

1. Simplex - 단방향

package ex20.ch01; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; // 단방향 통신 public class MyServer01 { public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(20000); // 서버소캣 생성 System.out.println("서버소켓 대기중입니다. 연결을 시도해주세요"); Socket socket = ss.accept(); // 프로세스 대기 System.out.println("소켓이 연결되었습니다"); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String body = br.readLine(); System.out.println("서버측 : " + body); } catch (IOException e) { throw new RuntimeException(e); } } }
package ex20.ch01; import java.io.*; import java.net.Socket; // 단방향 public class MyClient01 { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 20000); // 소켓 연결 BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in)); System.out.println("키보드 입력 대기중..."); String msg = keyboard.readLine(); // 여기서 멈춰있음 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write(msg); bw.write("\n"); bw.flush(); } catch (IOException e) { throw new RuntimeException(e); } } }
  • [서버] ServerSocket은 을의 요청을 기다리는 소캣이고 포트 변호로 10000을 가지고 있다.
    • 클라이언트의 연결을 받는게 유일한 일이다. 리스너.
    • IP주소를 받지 않는 이유는 갑이기 때문. 가만히 있으면 을이 온다.
    • 클라이언트와 연결되면 이 소켓은 연결을 끊고 사라짐.
  • [클라이언트] socket : 이 소켓을 만드는데 필요한 조건은 IP주소와 포트번호이다.
    • IP주소를 통해 목적지 컴퓨터까지 가게되고
    • 포트번호를 통해 프로세스를 찾는다
  • [서버] socket : 클라이언트와 연결되면 이 소캣을 새로 만들고 연결된다.
    • accept로 클라이언트가 연결되기를 기다린다. 리스너임(요청을 보냈는지 시간을 쪼개서 계속해서 확인)
    • 포트번호는 랜덤이다. 오히려 나음. 왜냐하면 포트번호는 0~65535까지이고 유명한 포트가 0~1023인데 커스텀하게 설정하면 중복이 발생할 수 있기 때문에.
  • [클라이언트] writer(BufferedWriter) : 1)write 2)flush한다.
    • 버퍼는 8192바이트로 크다
    • write로 내용을 담는다
    • 버퍼가 꽉 차지 않았기 때문에 flush로 강제적으로 보낸다.
    • 그러면 버퍼안에 있는 글자가 비워지면서 ByteStream으로 흘러감
  • [서버] reader(BufferedReader) : 1) readLine()으로 받아서 2) 처리
    • 위의 예제 코드에서는 처리하는 과정 없음
    • 읽기 위해 inputStream달았음.
    • 버퍼에 있는 걸 읽는 걸 readLine이 해준다. 자바에서는 조건이 \n까지 읽는 것.
    • readLine()도 리스너. \이 있어야 읽지만 \n은 안 읽음.

2. Half Duflex - 반이중

package ex20.ch02; import java.io.*; import java.net.ServerSocket; import java.net.Socket; // (반이중) public class MyServer02 { public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(20000); System.out.println("서버소켓 대기중입니다. 연결을 시도해주세요"); Socket socket = ss.accept(); // 프로세스 대기 System.out.println("소켓이 연결되었습니다"); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String reqbody = br.readLine(); String respbody = ""; // 프로토콜 if (reqbody.equals("name")) { respbody = "metacoding"; } else if (reqbody.equals("age")) { respbody = "39"; } else { respbody = "error"; } BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write(respbody); bw.write("\n"); bw.flush(); } catch (IOException e) { throw new RuntimeException(e); } } }
package ex20.ch02; import java.io.*; import java.net.Socket; // (반이중) public class MyClient02 { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 20000); // 소켓 연결 BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in)); System.out.println("키보드 입력 대기중..."); String reqBody = keyboard.readLine(); // 여기서 멈춰있음 name, age BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write(reqBody); bw.write("\n"); bw.flush(); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String respBody = br.readLine(); System.out.println(respBody); } catch (IOException e) { throw new RuntimeException(e); } } }
  • [클라이언트] Get 요청 = 자원(ex - html 페이지)을 주세요!
    • 요청을 분기할 수 있다. 다시 말해, html, xml을 구분해서 요청할 수 있다.
      • 따라서, 클라이언트는 정확한 메세지 프로토콜을 알아야 한다. 이 프로토콜은 갑인 서버가 만들었으니 인터페이스임.
  • [서버] 읽음
  • [서버] 응답 - 자원(ex - html 페이지)를 보낸다.
    • 어떤 요청이냐에 따라 다른 자원을 보낼 수 있음. html, xml등 조건에 따라 다른 걸 보내줄 수 있음.
    • 이 조건(프로토콜)은 서버가 만듬. 그래서 서버가 갑. 이 조건을 인터페이스라고 함.
  • [클라이언트] 읽음

3. Mutilplex(전이중)

package ex20.ch03; import java.io.*; import java.net.Socket; // (전이중) public class MyClient03 { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 20000); // 소켓 연결 // 1. 쓰기 분신 BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); new Thread(() -> { while (true) { try { String reqbody = keyboard.readLine(); bw.write(reqbody); bw.write("\n"); bw.flush(); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); // 2. 읽기 분신 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); new Thread(() -> { while (true) { try { String resqbody = br.readLine(); System.out.println("서버로 부터 받음 메시지 : " + resqbody); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); } catch (IOException e) { throw new RuntimeException(e); } } }
package ex20.ch03; import java.io.*; import java.net.ServerSocket; import java.net.Socket; // (전이중) public class MyServer03 { public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(20000); System.out.println("서버소켓 대기중입니다. 연결을 시도 해주세요"); Socket socket = ss.accept(); // 프로세스 대기 System.out.println("소켓이 연결되었습니다"); // 1. 쓰기 분신 BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); new Thread(() -> { while (true) { try { String reqBody = keyboard.readLine(); // 쓰기 쓰레드 대기 bw.write(reqBody); bw.write("\n"); bw.flush(); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); // 2. 읽기 분신 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); new Thread(() -> { while (true) { try { String respBody = br.readLine(); System.out.println("받은 메시지 : " + respBody); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); } catch (IOException e) { throw new RuntimeException(e); } } }

4. 채팅

package ex20.ch04; import java.io.*; import java.net.Socket; public class MyClient04 { public static void main(String[] args) { try { Socket socket = new Socket("192.168.0.99", 20000); // 소켓 연결 // 1. 쓰기 분신 BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); new Thread(() -> { while (true) { try { String reqBody = keyboard.readLine(); bw.write(reqBody); bw.write("\n"); bw.flush(); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); new Thread(() -> { while (true) { try { String respBody = br.readLine(); System.out.println("서버로 부터 받은 메시지 : " + respBody); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); } catch (IOException e) { throw new RuntimeException(e); } } }
package ex20.ch04; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; // Multiflex (채팅) public class MyServer04 { private List<ManagerThread> threads = new ArrayList<>(); class ManagerThread extends Thread { private String username; // s1, s2, s3 private Socket socket; private BufferedReader br; private BufferedWriter bw; public ManagerThread(Socket socket) { this.socket = socket; try { this.br = new BufferedReader(new InputStreamReader(socket.getInputStream())); this.bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); } catch (Exception e) { throw new RuntimeException(e); } } public void setUsername() { try { username = br.readLine(); System.out.println(username + " connected"); } catch (IOException e) { throw new RuntimeException(e); } } public String getUsername() { return username; } @Override public void run() { send("당신의 아이디를 전달해주세요"); setUsername(); send("당신의 아이디는 " + getUsername() + "입니다"); while (true) { try { String msg = br.readLine(); // 1. 파싱 String[] sps = msg.split(":"); // ALL:msg, ssar:msg String protocal = sps[0]; String body = sps[1]; // 2. 프로토콜 분석 if (protocal.equals("ALL")) { for (ManagerThread mt : threads) { mt.send(body); // 전체 메시지 } } else { for (ManagerThread mt : threads) { if (protocal.equals(mt.getUsername())) { mt.send(body); // 귓속말 } } } } catch (Exception e) { throw new RuntimeException(e); } } } public void send(String msg) { try { bw.write(msg); bw.write("\n"); bw.flush(); } catch (Exception e) { throw new RuntimeException(e); } } } public MyServer04() { try { ServerSocket serverSocket = new ServerSocket(20000); while (true) { Socket socket = serverSocket.accept(); ManagerThread mt = new ManagerThread(socket); threads.add(mt); mt.start(); // 분신 } } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { new MyServer04(); } }
Share article

gunwoo