[Network] socket통신

Benjamin·2023년 6월 2일
0

Network

목록 보기
4/4

소켓 프로그래밍

소켓

  • 네트워크 상에서 수행되는 두 프로그램 간 양방향 통신링크의 한쪽 끝 단을 의미

  • 소켓은 특정 포트 번호와 연결되어 있음
    -> TCP에서 데이터를 보낼 응용 프로그램을 식별할 수 있음 ex) 웹서버는 80포트 이용

  • 자바에서의 데이터 통신 시 소켓 사용

  • 소켓 종류
    -> 서버 소켓과 클라이언트 소켓

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

  • Server(ServerSocket)이 하는일은 접속이 들어왔을 때 새로운 소켓을 만들어주는 일밖에 없다
  • 통신은 클라이언트와 소켓에서 왔다갔다함
  • 서버 하나는 여러 클라이언트와 붙을 수 있다.

Socket 클래스

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

    -> 주소와 포트를 갖고있어야한다.
    -> 인터넷 주소를 가질수도있고, 문자열로 된 주소를 가질수도 있음
    -> 포트를 갖고 접속

Socket 클래스의 주요 메소드

  • getInputStream() : 읽어오고
  • getOutputStream() : 쓰는것

소켓 생성, 서버 접속, 입출력 스트림 생성

  • 클라이언트 소켓 생성 및 서버에 접속
    -> Socket 객체 생성되면 곧 바로 128.12.1.1의 주소로 자동 접속

  • 네트워크 입출력 스트림 생성
    읽기위해 : BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getIntputStream()));
    쓰기위해 : BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
    -> 일반 스트림을 입출력하는 방식과 동일

  • 서버로 데이터 전송
    -> flush()를 호출하면 스트림 속에 데이터를 남기지않고 모두 전송

out.write("hello" + "\n");
out.flush();
  • 서버로부터 데이터 수신
int x = in.read(); //서버로부터 한 개의 문자 수신
String line = in.readline(); //서버로부터 한 행의 문자열 수신
  • 네트워크 접속 종료
    clientSocket.close();

ServerSocket 클래스, 서버 소켓

  • 서버 소켓에 사용되는 클래스

  • java.net 패키지에 포함

  • 주요 생성자

  • 주요 메소드

    -> accept() : 새 소켓 객체를 만들어서, 클라이언트와 연결되게 하는것

클라이언트와 서버

클라이언트와 서버 연결

  • 서버는 서버 소켓으로 들어오는 연결 요청을 기다림

  • 클라이언트가 서버에게 연결 요청 (특정 포트번호로 접속)

  • 서버가 연결 요청을 수락하고, 새로운 소켓을 만들어 클라이언트와 연결 생성
    (빨간 박스 = 새로운 소켓)

소켓 생성, 클라이언트 접속, 입출력 스트림 생성

  • 서버 소켓 생성
    -> 이미 사용중인 포트 번호를 지정하면 오류가 발생
    ServerSocket serverSocket = new ServerSocket(5550);

  • 클라이언트로부터 접속 기다림
    Socket socket = servetSocket.accept();
    -> accept()메소드는 연결 요청이 오면 새로운 Socket 객체 반환
    -> 서버에서 클라이언트와의 데이터 통신은 새로 만들어진 Socket 객체를 통해서 이루어짐
    -> ServerSocket 클래스는 Socket 클래스와 달리 주어진 연결에 대해 입출력 스트림을 만들어주는 메소드가 없음

  • 네트워크 입출력 스트림 생성

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.OutputStream()));

-> accept() 메소드에서 얻은 Socket객체의 getInputStream()과 getOutputStream()메소드를 이용하여 데이터 스트림 생성
-> 일반 스트림을 입출력하는 방식과 동일하게 네트워크 데이터 입출력

클라이언트로 데이터 송수신

  • 클라이언트로부터 데이터 수신
int x = in.read(); //클라이언트로부터 한 개의 문자 수신
String line = in.readline(); //클라이언트로부터 한 행의 문자열 수신
  • 클라이언트로 데이터 전송
out.write("Hi!, Client" + "\n");
out.flush();

-> flush()를 호출하면 스트림 속에 데이터를 남기지 말고 모두 전송

  • 네트워크 접속 종료
    socket.close();
    -> 만들었던 소켓을 없애야하고

  • 서버 응용프로그램 종료
    serverSocket.close();
    -> 더 이상 클라이언트의 접속을 받지 않고 서버 응용 프로그램을 종료하고자 하는 경우 ServerSocket 종료
    -> 서버 종료

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

간단한 채팅 프로그램 예제

  • 서버와 클라이언트가 1:1로 채팅하는 간단한 예제
    -> 스레드 사용x. 무전기처럼 단방향.. 순서가 있음 (클라가 무조건 먼저 연결, 서버는 연결받은 다음 쓰고...)
  • 서버와 클라이언트 간의 메시지 구분을 위해 서버는 메시지 앞에 "서버>"를 붙여 메시지 전송하며, 클라이언트는 "클라이언트>"를 접두어로 붙여 메시지 전송
  • 서버와 클라이언트가 번갈아 가면서 메시지 전송 및 수신
  • 클라이언트가 bye를 보내면 프로그램 종료

서버 프로그램

  • 서버 소켓 생성
    ServerSocket listener = new ServerSocket(9999);
    -> 시스템에서 사용되지 않은 포트 번호로 서버 소켓 생성

  • 클라이언트 요청 대기
    Socket socket = listener.accept();
    -> 클라이언트가 연결 요청이 올 때까지 소켓 기다림
    -> 해당 포트 번호로 연결 요청이 오면 수락과 함께 새로운 소켓을 생성 / 새 소켓으로 클라이언트와 통신
    -> 새로운 소켓의 포트 번호는 자동으로 할당

  • 클라이언트와 통신을 위한 입출력 스트림 생성

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.OutputStream()));

-> 스트림을 생성하여 클라이언트와 데이터 송수신

  • 데이터 종류에 따라 바이트 스트림 또는 문자 스트림을 생성

  • 채팅과 같이 문자열을 송수신하는 경우는 문자 스트림 사용

  • 효율적 입출력을 위하여 버퍼 스트림(Buffered Stream) 사용

  • 클라이언트의 데이터 수신
    String inputMessage = in.readLine();
    -> 스트림 생성 이후는 데이터 입력 받는 방법과 동일
    -> 클라이언트에서 한 행의 문자열을 보내올 때까지 기다림

  • 클라이언트에 데이터 송신

String outputMessage = stin.readLine();
out.write("서버>" + outputMessage + "\n");
out.flush();

-> 스트림 생성 이후는 일반 데이터를 출력하는 방법과 동일
-> 콘솔에서 입력 받은 문자열을 클라이언트로 송신
-> flush() 메소드로 스트림의 모든 데이터를 클라이언트로 송신

  • 연결 종료
socket.close();
listener.close();

-> 데이터의 송수신이 끝나면 소켓을 닫아야함
-> 소켓을 닫으면 소켓의 입출력 스트림도 같이 닫힘
-> 서버 소켓을 닫으면 클라이언트 연결 요청을 받을 수 없음

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ServerEx {
    public static void main(String[] args) {
        ServerSocket server = null; 
        Socket socket = null;
        BufferedReader in = null;
        BufferedWriter out = null;
        Scanner sc = new Scanner(System.in);

        try {
            server = new ServerSocket(9999); //이미 사용중인 포트면 에러발생
            System.out.println("연결 대기중.....");

            socket = server.accept();
            System.out.println("연결 되었습니다.");

            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            while(true) {
                String inMsg = in.readLine();
                if(inMsg.equalsIgnoreCase("bye")) {
                    System.out.println("클라이언트가 나갔습니다.");
                    break;
                }

                //정상 메시지인 경우
                System.out.println("클라이언트 : " + inMsg);

                System.out.print("보내기 >>");
                String outMsg = sc.nextLine();
                out.write(outMsg + "\n");
                out.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try{
                sc.close();
                out.close();
                in.close();
                socket.close();
                server.close();
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

지금은 콘솔에서 입력받기때문에 커서가 입력받을 때까지 계속 대기상태로 기다리고있지만, GUI로 동작하게하면 기다리지않고, 들어오면 동작하게 처리가능


출처
https://www.youtube.com/watch?v=dX82Wuc18wk
https://kadosholy.tistory.com/125

0개의 댓글