TCP 소켓 프로그래밍 (23.05.12)

·2023년 5월 12일
0

Java

목록 보기
31/35
post-thumbnail

📝 네트워크


💡 서버와 클라이언트

네트워크로 연결된 컴퓨터간의 관계를 역할(role)로 구분한 개념

  • 서버 : 서비스를 제공하는 프로그램 또는 컴퓨터
  • 클라이언트 : 서비스를 요청하여 사용하는 프로그램 또는 컴퓨터

💡 IP 주소

네트워크 상에서 컴퓨터를 식별하는 번호
-> 네트워크 어댑터(랜카드)마다 할당 되어 있음

💡 포트(Port)

같은 컴퓨터 내에서 프로그램을 식별하는 번호
-> 클라이언트는 서버 연결 요청 시 IP주소와 포트 번호를 알아야 함


📝 소켓 프로그래밍


💡 소켓(Socket)

  • 프로세스 간의 통신에 사용되는 양쪽 끝 단
  • 서버와 클라이언트가 통신을 하기 위한 매개체
  • ServerSocket (서버용 소켓)
    : Port와 연결되어 외부 요청을 기다리는 역할
    -> 클라이언트 요청이 올 경우 이를 수락(accept)하고 클라이언트가 사용할 수 있는 소켓을 생성
    -> 서버 소켓과 클라이언트 소켓이 연결되어 데이터 통신이 가능해짐

💡 프로토콜(Protocol)

  • 컴퓨터 간의 정보를 주고 받을 때의 통신방법에 대한 규약
  • 접속이나, 전달방식, 데이터의 형식, 검증 방법 등을 맞추기 위한 약속

💡 TCP(Transmission Control Protocol)

데이터 전달의 신뢰성을 최대한 보장하기 위한 방식(연결 지향형 통신)
-> 순차적으로 데이터를 전달하고 확인 및 오류 시 재전송

💡 UDP(User Datagram Protocol)

데이터의 빠른 전달을 보장하기위한 방식으로 비연결 지향형 통신
-> 확인 및 재전송 작업이 없음


📝 TCP 소켓 프로그래밍


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

  • 서버가 먼저 실행되어 클라이언트의 요청을 기다려야 하고 서버용 프로그램과 클라이언트용 프로그램을 따로 구현해야 함
  • 자바에서는 TCP 소켓 프로그래밍을 위해 java.net패키지에서 ServerSocket과 Socket클래스 제공

✏️ 서버용 TCP 소켓 프로그래밍 순서

  1. 서버의 포트번호 정함
  2. 서버용 소켓 객체 생성
  3. 클라이언트 쪽에서 접속 요청이 오길 기다림
  4. 접속 요청이 오면 요청 수락 후 해당 클라이언트에 대한 소켓 객체 생성
  5. 연결된 클라이언트와 입출력 스트림 생성
  6. 보조 스트림을 통해 성능 개선
  7. 스트림을 통해 읽고 쓰기
  8. 통신 종료

✏️ 클라이언트용 TCP 소켓 프로그래밍 순서

  1. 서버의 IP주소와 서버가 정한 포트번호를 매개변수로 하여 클라이언트용 소켓 객체 생성
  2. 서버와의 입출력 스트림 오픈
  3. 보조 스트림을 통해 성능 개선
  4. 스트림을 통해 읽고 쓰기
  5. 통신 종료

✏️ 예제 1-1. 서버용 TCP 소켓 프로그래밍 순서 알아보기

이클립스로 workspace를 두 개 만들어 하나는 서버용, 하나는 클라이언트용으로 쓸 예정이다.

[서버용 workspace]

  • TCPServer 클래스
	public void serverStart() {
		
		// 1. 서버의 포트번호 정함
		int port = 8500; // port 번호는 0 ~ 65535 사이 지정 가능
						// 단, 1023번 이하는 이미 사용 중인 경우가 많으니 제외
		
		// * 사용할 변수를 미리 선언 *
		ServerSocket serverSocket = null; // 서버 소켓 저장 변수
		Socket clientSocket = null; // 클라이언트 소켓 저장 변수
		
		InputStream is = null; // 클라이언트 -> 서버 입력용 스트림 변수
		BufferedReader br = null; // 입력용 보조 스트림 변수
		
		OutputStream os = null; // 서버 -> 클라이언트 출력용 스트림 변수
		PrintWriter pw = null; // 출력용 보조 스트림 변수
		
		try {
			// 2. 서버용 소켓 객체 생성
			serverSocket = new ServerSocket(port); // 서버용 소켓을 생성하여 포트 결합
			
			
			// 3. 클라이언트 쪽에서 접속 요청이 오길 기다림
			// - 서버용 소켓은 생성되면 클라이언트 요청이 오기 전가지
			//	 다음 코드를 수행하지 않고 대기하고 있음
			System.out.println("[Server]");
			System.out.println("클라이언트 요청을 기다리고 있습니다.");
			
			
			// 4. 접속 요청이 오면 요청 수락 후 해당 클라이언트에 대한 소켓 객체 생성
			// -> 요청을 수락하면 자동으로 Socket 객체가 얻어와짐
			clientSocket = serverSocket.accept();
			
			// 접속한 클라이언트의 IP를 얻어와 출력
			String clientIP = clientSocket.getInetAddress().getHostAddress();
			System.out.println(clientIP + "가 연결을 요청함...");
			
			
			// 5. 연결된 클라이언트와 입출력 스트림 생성
			is = clientSocket.getInputStream();
			os = clientSocket.getOutputStream();
			
			
			// 6. 보조 스트림을 통해 성능 개선
			br = new BufferedReader(new InputStreamReader(is));
			// InputStreamReader : 문자 기반 스트림과 바이트 기반 스트림 연결에 사용되는 스트림
			
			pw = new PrintWriter(os);
			
			
			// 7. 스트림을 통해 읽고 쓰기
			
			// 7-1) 서버 -> 클라이언트에게 출력(메시지 전송)
			
			Date now = new Date(); // 생성된 시간을 기록하고 있는 시간 관련 객체
			
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			
			String time = sdf.format(now); // now에 저장된 시간 포맷을 변경
			
			pw.println(time + "[서버 접속 성공]");
			pw.flush(); // 스트림에 있는 내용을 모두 밀어냄
			
			// 7-2) 클라이언트 -> 서버에게 입력(메시지 전송 받기)
			
			String message = br.readLine(); // 클라이언트 메시지 한 줄을 읽어옴
			
			System.out.println(clientIP + "가 보낸 메시지 : " + message);
			
		} catch (IOException e) {
			e.printStackTrace(); // 예외 추적
			
		} finally {
			// 8. 통신 종료
			
			// 사용한 스트림, 소켓 자원을 모두 반환(close)
			try {
				// 보조스트림 close 시 연결된 기반 스트림(is, os)도 같이 close 된다.
				if(pw != null) 				pw.close();
				if(br != null) 				br.close();
				
				if(serverSocket != null) 	serverSocket.close();
				if(clientSocket != null)	clientSocket.close();
				
				// if문에 { }를 사용 안 하면 다음 한 줄(세미콜론 기준)이 if문 내부 코드가 된다.
			} catch(IOException e) {
				
			}
		}
	}
  • TCPServer 클래스
package edu.kh.network.run;

import edu.kh.network.model.service.TCPServer;

public class ServerRun {

	public static void main(String[] args) {
		TCPServer server = new TCPServer();
		server.serverStart();
		
	}
}

✏️ 예제 1-2. 클라이언트용 TCP 소켓 프로그래밍 순서 알아보기

[클라이언트용 workspace]

  • TCPClient 클래스
package edu.kh.network.model.service;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {
	
	public void clientStart() {
		
		// 1. 서버의 IP주소와 서버가 정한 포트번호를 매개변수로 하여 클라이언트용 소켓 객체 생성
		
		String serverIP = "127.0.0.1"; // loop back ip (내 컴퓨터를 가리키는 ip 주소)
		int port = 8500; // 서버 소켓이 기다리고 있는 포트 번호 작성
		
		// * 필요한 변수 선언 *
		
		Socket clientSocket = null; // 서버와 연결한 클라이언트용 소켓을 저장할 변수
		
		BufferedReader br = null; // 서버 -> 클라이언트로 읽어 오는 보조 스트림
		
		PrintWriter pw = null; // 클라이언트 -> 서버로 출력하는 보조 스트림
		
		try {
			// 2. 서버와의 입출력 스트림 오픈
			System.out.println("[Client]");
			
			clientSocket = new Socket(serverIP, port);
						// throws UnknownHostException, IOException
			
			// 3. 보조 스트림을 통해 성능 개선
			// 2, 3번 동시 진행
			br = new BufferedReader( new InputStreamReader(clientSocket.getInputStream() ) );
			
			pw = new PrintWriter( clientSocket.getOutputStream() );
			
			// 4. 스트림을 통해 읽고 쓰기
			// 4-1) 서버 접속 성공 시
			//		서버가 출력한 "[서버 접속 성공]" 메시지 읽어오기
			String message = br.readLine();
			System.out.println("서버로부터 받은 메시지 : " + message);
			
			// 4-2) 클라이언트 -> 서버로 메시지 전송
			Scanner sc = new Scanner(System.in);
			System.out.print("입력 : ");
			String input = sc.nextLine();
			
			pw.println(input);
			pw.flush();

			
		} catch (Exception e) {
			// UnknownHostException, IOException 한 번에 처리

		} finally {
			// 5. 통신 종료
			try {
				
				if(pw != null) pw.close();
				if(br != null) br.close();
				if(clientSocket != null) clientSocket.close();
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
  • ClientRun 클래스
package edu.kh.network.run;

import edu.kh.network.model.service.TCPClient;

public class ClientRun {
	public static void main(String[] args) {

		TCPClient client = new TCPClient();
		
		client.clientStart();
		
	}

}

[출력 화면]

  • 서버용 workspace
  • 클라이언트용 workspace

서버와 클라이언트가 연결되어 서로의 내용을 주고받는 결과를 볼 수 있다.

profile
풀스택 개발자 기록집 📁

0개의 댓글