JUINTINATION

소켓 프로그래밍 본문

자바프로그래밍및실습

소켓 프로그래밍

DEOKJAE KWON 2023. 1. 6. 21:57
반응형

소켓(Socket)이란?

TCP/IP 네트워크를 이용하여 쉽게 통신 프로그램을 작성하도록 지원하는 기반 기술
  • 두 응용프로그램 간의 양방향 통신 링크의 한쪽 끝 단
  • 소켓끼리 데이터를 주고받음
  • 소켓은 특정 IP 포트 번호와 결합
  • 소켓 종류 : 서버 소켓과 클라이언트 소켓
  • TCP는 Transmission Control Protocol
  • 두 시스템 간에 신뢰성 있는 데이터의 전송을 관장하는 프로토콜
  • TCP에서 동작하는 응용프로그램 사례
    • e-mail, FTP, 웹(HTTP) 등
  • IP는 Internet Protocol
    • 패킷 교환 네트워크에서 송신 호스트와 수신 호스트가 데이터를 주고 받는 것을 관장하는 프로토콜
    • TCP보다 하위 레벨 프로토콜

IP 주소

  • 네트워크 상에서 유일하게 식별될 수 있는 컴퓨터 주소
    • 숫자로 구성된 주소
    • 4개의 숫자가 ‘.’으로 연결
      • 예) 192.156.11.15
  • 숫자로 된 주소는 기억하기 어려우므로 www.naver.com과 같은 문자열로 구성된 도메인 이름으로 바꿔 사용
    • DNS(Domain Name Server)
      • 문자열로 구성된 도메인 이름을 숫자로 구성된 IP 주소로 자동 변환
  • 현재는 32비트의 IP 버전 4(IPv4)가 사용되고 있음
    • IP 주소 고갈로 인해 128비트의 IP 버전 6(IPv6)이 점점 사용되는 추세
  • 윈도우에서 cmd을 실행한 뒤에 ipconfig 실행하여 IPv4 주소 확인

포트(Port)

  • 통신하는 프로그램 간에 가상의 연결단 포트 생성
    • IP 주소는 네트워크 상의 컴퓨터 또는 시스템을 식별하는 주소
    • 포트 번호를 이용하여 통신할 응용프로그램 식별
  • 모든 응용프로그램은 하나 이상의 포트 생성 가능
    • 포트를 이용하여 상대방 응용프로그램과 데이터 교환
  • 잘 알려진 포트(well-known ports)
    • 시스템이 사용하는 포트 번호
    • 잘 알려진 응용프로그램에서 사용하는 포트 번호
      • 0부터 1023 사이의 포트 번호
      • ex) 텔넷 23, HTTP 80, FTP 21
  • 잘 알려진 포트 번호는 충돌 가능성이 있기 때문에 개발자가 사용하지 않는 것이 좋음

소켓을 이용한 서버 클라이언트 통신 프로그램의 전형적인 구조

Socket 클래스, 클라이언트 소켓

  • 클라이언트 소켓에 사용되는 클래스
  • java.net 패키지에 포함
  • 생성자

Socket 클래스의 메소드

클라이언트에서 소켓으로 서버에 접속하는 코드

// 클라이언트 소켓 생성 및 서버 접속
Socket clientSocket = new Socket("ipAddress", portNum);

// 소켓으로부터 데이터를 전송할 입출력 스트림 생성
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

// 서버로 데이터 전송
out.write("hello"+"\n");
out.flush(); // flush() 메소드로 스트림 속 데이터를 남기지 않고 모두 전송

// 서버로부터 데이터 수신
String line = in.readline(); // 서버로부터 한 행의 문자열 수신

// 네트워크 접속 종료
clientSocket.close();

ServerSocket 클래스, 서버 소켓

  • 서버 소켓에 사용되는 클래스, java.net 패키지에 포함
  • 서버에 접근하는 클라이언트 소켓의 연결 요청을 기다리는 일종의 listener 역

 

서버가 소켓으로 클라이언트 접속하는 코드

// 서버 소켓 생성
ServerSocket serverSocket = new ServerSocket(portNum);

// 클라이언트로부터 접속 기다림
Socket socket = serverSocket.accept();

/*
 // accept() 메소드는 연결 요청이 오면 새로운 Socket 객체 반환
 // 접속 후 새로 만들어진 Socket 객체를 통해 클라이언트와 통신
 */

// 네트워크 입출력 스트림 생성
// Socket 객체의 getInputStream()과 getOutputStream() 메소드를 이용하여 입출력 데이터 스트림 생성
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

// 클라이언트로 데이터 전송
out.write("hello"+"\n");
out.flush(); // flush() 메소드로 스트림 속 데이터를 남기지 않고 모두 전송

// 클라이언트로부터 데이터 수신
String line = in.readline(); // 서버로부터 한 행의 문자열 수신

// 서버 소켓 닫기
serverSocket.close();

소켓을 이용한 서버/클라이언트 채팅 예제

  • 간단한 채팅 프로그램
    • 서버와 클라이언트가 1:1로 채팅
    • 클라이언트와 서버가 서로 한번씩 번갈아 가면서 문자열 전송
      • 문자열 끝에 "\n"을 덧붙여 보내고 라인 단위로 수신
    • 클라이언트가 bye를 보내면 프로그램 종료

서버 프로그램

import java.io.*;
import java.net.*;
import java.util.*;

public class ServerEx {
    public static void main(String[] args) {
        BufferedReader in = null;
        BufferedWriter out = null;
        ServerSocket listener = null;
        Socket socket = null;
        Scanner scanner = new Scanner(System.in); // 키보드에서 읽을 scanner 객체 생성
        try {
            listener = new ServerSocket(9999); // 서버 소켓 생성
            System.out.println("연결을 기다리고 있습니다.....");
            socket = listener.accept(); // 클라이언트로부터 연결 요청 대기
            System.out.println("연결되었습니다.");
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            while (true) {
                String inputMessage = in.readLine(); // 클라이언트로부터 한 행 읽기
                if (inputMessage.equalsIgnoreCase("bye")) {
                    System.out.println("클라이언트에서 bye로 연결을 종료하였음");
                    break; // "bye"를 받으면 연결 종료
                }
                System.out.println("클라이언트: " + inputMessage);
                System.out.print("보내기>>"); // 프롬프트
                String outputMessage = scanner.nextLine(); // 키보드에서 한 행 읽기
                out.write(outputMessage + "\n"); // 키보드에서 읽은 문자열 전송
                out.flush(); // out의 스트림 버퍼에 있는 모든 문자열 전송
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                scanner.close(); // scanner 닫기
                socket.close(); // 통신용 소켓 닫기
                listener.close(); // 서버 소켓 닫기
            } catch (IOException e) {
                System.out.println("클라이언트와 채팅 중 오류가 발생했습니다.");
            }
        }
    }
}

클라이언트 프로그램

import java.io.*;
import java.net.*;
import java.util.*;

public class ServerEx {
    public static void main(String[] args) {
        BufferedReader in = null;
        BufferedWriter out = null;
        ServerSocket listener = null;
        Socket socket = null;
        Scanner scanner = new Scanner(System.in); // 키보드에서 읽을 scanner 객체 생성
        try {
            listener = new ServerSocket(9999); // 서버 소켓 생성
            System.out.println("연결을 기다리고 있습니다.....");
            socket = listener.accept(); // 클라이언트로부터 연결 요청 대기
            System.out.println("연결되었습니다.");
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            while (true) {
                String inputMessage = in.readLine(); // 클라이언트로부터 한 행 읽기
                if (inputMessage.equalsIgnoreCase("bye")) {
                    System.out.println("클라이언트에서 bye로 연결을 종료하였음");
                    break; // "bye"를 받으면 연결 종료
                }
                System.out.println("클라이언트: " + inputMessage);
                System.out.print("보내기>>"); // 프롬프트
                String outputMessage = scanner.nextLine(); // 키보드에서 한 행 읽기
                out.write(outputMessage + "\n"); // 키보드에서 읽은 문자열 전송
                out.flush(); // out의 스트림 버퍼에 있는 모든 문자열 전송
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                scanner.close(); // scanner 닫기
                socket.close(); // 통신용 소켓 닫기
                listener.close(); // 서버 소켓 닫기
            } catch (IOException e) {
                System.out.println("클라이언트와 채팅 중 오류가 발생했습니다.");
            }
        }
    }
}​

내 생각

수업 시간에 소켓 프로그래밍에 대해 배우면서 채팅 프로그램을 만들라며 교수님이 기말 프로젝트 과제를 내주셨습니다. 앞서 설명하셨던 스레드, Swing 등을 이용하는 과제였는데 이는 위의 예제에서 그룹 채팅 기능과 실시간으로 그림이 그려지는 그림판 기능을 추가해야 했습니다. 처음에 너무 막막했지만 프로젝트를 진행하면서 이론만으로는 이해하기 힘들었던 소켓 프로그래밍에 대해 이해하게 된 좋은 기회였던 것 같습니다.

728x90

'자바프로그래밍및실습' 카테고리의 다른 글

JDBC 프로그래밍  (0) 2023.01.08
스레드와 멀티태스킹  (0) 2023.01.03
제네릭과 컬렉션  (0) 2022.12.22
Comments