Java/Java

네트워크 프로토콜

DDG9 2024. 5. 24. 15:34

네트워크 프로토콜이란?

네트워크 프로토콜은 네트워크에서 데이터를 교환하기 위한 규칙과 절차의 집합입니다.

프로토콜은 데이터 형식, 순서, 오류 제어 등을 정의하여 서로 다른 시스템 간의 통신을 가능하게 합니다.

 

주요 프로토콜

  1. HTTP (HyperText Transfer Protocol): 웹 페이지를 전송하기 위한 프로토콜입니다.
  2. TCP (Transmission Control Protocol): 신뢰성 있는 데이터 전송을 보장하는 프로토콜입니다.
  3. UDP (User Datagram Protocol): 신뢰성보다는 빠른 전송을 중시하는 프로토콜입니다.
  4. FTP (File Transfer Protocol): 파일 전송을 위한 프로토콜입니다.
  5. SMTP: 이메일 전송을 위한 프로토콜입니다.

프로토콜은 각기 다른 목적을 가지고 있습니다

  • TCP/IP: 인터넷과 대부분의 네트워크에서 사용되는 프로토콜 스택입니다.
  • HTTP/HTTPS: 웹 브라우징을 위한 프로토콜입니다.
  • FTP: 파일 전송을 위한 프로토콜입니다.
  • SMTP: 이메일 전송을 위한 프로토콜입니다.

 

💡 반드시 구분할 것 !!

소켓은 네트워크 통신을 위해 필요한 인터페이스를 제공하고 네트워크 프로토콜은 네트워크 상에서 데이터를 교환하는 규칙과 절차를 정의한 것

 

[ 클라이언트 프로그램 ]                              [ 서버 프로그램 ]
+----------------------+                             +----------------------+
|                      |                             |                      |
|  +---------------+   |                             |   +---------------+  |
|  |               |   |                             |   |               |  |
|  |   소켓        |<--------------------------------|-->|   소켓        |  |
|  |   (IP:Port)   |   |                             |   |   (IP:Port)   |  |
|  +---------------+   |                             |   +---------------+  |
|          ^           |                             |           ^          |
|          |           |                             |           |          |
|   +------+------     |                             |    +------+------    |
|   |  TCP/IP   |      |                             |    |  TCP/IP   |     |
|   +---------- +      |                             |    +---------- +     |
|          ^           |                             |           ^          |
|          |           |                             |           |          |
| +--------+-------+   |                             |  +--------+-------+  |
| | 프로토콜 계층  |   |                             |  | 프로토콜 계층  |  |
| | (HTTP, FTP 등) |   |                             |  | (HTTP, FTP 등) |  |
| +----------------+   |                             |  +----------------+  |
|                      |                             |                      |
+----------------------+                             +----------------------+

[인터넷/네트워크]  <------------- 데이터 전송 --------------->  [인터넷/네트워크]

  • 소켓: 네트워크 통신을 위한 인터페이스로, IP 주소와 포트 번호로 구성됩니다. 소켓은 데이터를 송수신하기 위한 엔드포인트입니다.
  • 프로토콜: 네트워크 상에서 데이터를 교환하는 규칙과 절차를 정의합니다. 예를 들어, TCP/IP 프로토콜은 데이터의 전송과 오류 제어를 담당합니다.
  1. TCP/IP 프로토콜
    • TCP/IP 프로토콜은 데이터의 전송을 담당합니다. 이는 데이터를 작은 패킷으로 나누어 전송하고, 순서대로 재조립하며, 데이터의 신뢰성을 보장합니다.
    • 클라이언트와 서버는 TCP/IP 프로토콜을 사용하여 데이터를 주고받습니다.
  2. 프로토콜 계층
    • HTTP, FTP 등의 애플리케이션 계층 프로토콜은 데이터를 어떤 형식으로 주고받을지 정의합니다.
    • 예를 들어, HTTP는 웹 페이지를 주고받는 규칙을 정의하고, FTP는 파일 전송을 위한 규칙을 정의합니다.

통신 과정 - 클라이언트와 서버는 각각 소켓을 통해 연결을 설정하고, TCP/IP 프로토콜을 사용하여 데이터를 전송하며, 프로토콜 계층(예: HTTP 형식)을 통해 데이터를 해석하고 처리합니다.

 

 

시나리오 코드 1 - 나만의 프로토콜을 만들어서 서버를 구성해보자. 프로토콜 적용 요약

  1. 메시지 형식: "COMMAND:DATA" 형식을 사용합니다.
    • MSG:Hello 는 "Hello" 메시지를 전송합니다.
    • BYE: 는 연결 종료를 의미합니다.
  2. 클라이언트와 서버 간의 상호작용:
    • 클라이언트는 키보드 입력을 읽고 메시지를 서버에 전송합니다.
    • 서버는 클라이언트로부터 메시지를 수신하여 모든 클라이언트에게 브로드캐스트합니다.
    • 클라이언트가 "bye"를 입력하면 연결을 종료합니다.

 

클라이언트측 코드

package ch07;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class MultiClient {

	public static void main(String[] args) {

		try {
			Socket socket = new Socket("192.168.0.48", 5000);
			PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
			BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));

			System.out.println(">>> 서버에 접속 완료 <<<");

			// 실행의 흐름 - 약속 : 먼저 사용자 닉네임 보내기
			System.out.println("Enter your name : ");
			String name = keyboard.readLine();
			out.println("NAME:" + name); // 서버로 사용자 이름 전송

			// 서버측으로 부터 온 데이터 읽기
			Thread readThread = new Thread(() -> {
				try {
					String serverMsg;
					while ((serverMsg = in.readLine()) != null) {
						System.out.println("server : " + serverMsg);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			});

			// 클라이언트가 서버로 데이터 보내기
			Thread writeThread = new Thread(() -> {
				try {
					String userMessage;
					while ((userMessage = keyboard.readLine()) != null) {
						if (userMessage.equalsIgnoreCase("bye")) {
							out.println("BYE:");
						} else {
							out.println("MSG:" + userMessage);
						}
//						else if (userMessage.equalsIgnoreCase("MSG")) {
//							out.println("MSG:" + userMessage);
//						}
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			});

			// 스레드 시작
			readThread.start();
			writeThread.start();

			// 메인 스레드 대기
			readThread.join();
			writeThread.join();

			socket.close();
			System.out.println("서버로 부터 연결을 종료하였습니다");
		} catch (Exception e) {
			e.printStackTrace();
		}
	} // end of main
}

 

서버측 코드

package ch07;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

public class MultiClientServer {

	private static final int PORT = 5000;
	// 하나의 변수에 자원을 통으로 관리하기 기법 -> 자료 구조
	// 자료 구조 --> 코드 단일, 멀티 스레드
	// 객체 배열 <-- Vector<> : 멀티스레드에 안정적이다
	private static Vector<PrintWriter> clientWriters = new Vector<>();

	public static void main(String[] args) {
		System.out.println("Server started...");

		try (ServerSocket serverSocket = new ServerSocket(PORT)) {
			while (true) {
				Socket socket = serverSocket.accept();
				new ClientHandler(socket).start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	} // end of main

	// 정적 내부 클래스 설계
	private static class ClientHandler extends Thread {
		private Socket socket;
		private PrintWriter out;
		private BufferedReader in;

		public ClientHandler(Socket socket) {
			this.socket = socket;
		}

		// 스레드 start() 호출시 동작되는 메서드
		@Override
		public void run() {
			try {
				in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				out = new PrintWriter(socket.getOutputStream(), true);

				// 코드 추가
				// 클라이언트로부터 이름 받기(약속되어 있음 !)
				String nameMessage = in.readLine();
				if (nameMessage != null && nameMessage.startsWith("NAME:")) {
					String clientName = nameMessage.substring(5);
					broadcastMessage("해당 서버에 : " + clientName + " 님 입장");
				} else {
					// 약속과 다르게 접근했다면 종료 처리
					socket.close();
					return;
				}

				// 여기서 중요 ! - 서버가 관리하는 자료구조에 자원 저장
				clientWriters.add(out);

				String message;
				while ((message = in.readLine()) != null) {
					System.out.println("Received : " + message);

					// 약속
					// : 기준	으로 처리
					// MSG:안녕\n
					String[] parts = message.split(":", 2);
					System.out.println("parts 인덱스 갯수 : " + parts.length);
					// 명령 부분을 분리
					String command = parts[0];
					// 데이터 부분을 분리
					String data = parts.length > 1 ? parts[1] : "";

					if (command.equals("MSG")) {
						System.out.println("연결된 전체 사용자에게 MSG 방송");
						broadcastMessage(message);
					} else if (command.equals("BYE")) {
						System.out.println("Client disconnected ...");
						break;
					}
				}
			} catch (Exception e) {
//				e.printStackTrace();
			} finally {
				try {
					socket.close();
					// 도전 과제 !!
					// 서버측에서 관리하고 있는 PrintWriter 제거 해야한다.
					// 인덱스 번호가 필요하다.
					// clientWriters.add() 할 때 지정된 나의 인덱스 번호가 필요
					// clientWriters.remove();
					System.out.println("..... 클라이언트 연결 해제 .....");
				} catch (IOException e) {
//					e.printStackTrace();
				}
			}
		}
	} // end of ClientHandler

	// 모든 클라이언트에게 메세지 보내기 - 브로드캐스트
	private static void broadcastMessage(String message) {
		for (PrintWriter writer : clientWriters) {
			writer.println(message);
		}
	}
}

'Java > Java' 카테고리의 다른 글

소켓을 활용한 HTTP 통신  (0) 2024.06.03
제네릭 ( Generic )  (0) 2024.06.03
1:N 소켓 양방향 통신  (0) 2024.05.24
1:1 양방향 통신 ( 채팅 기본 기능 구현 )  (0) 2024.05.22
1:1 단방향 통신  (0) 2024.05.22