소켓 실습

Moom2n·2024년 3월 21일
0

Java

목록 보기
25/26

- Server Socket

  • ServerSocket class를 이용하며, socket을 생성하고 binding 과정까지 함께 수행

  • accept() 함수를 통해 client의 연결을 기다리며, 연결에 성공한 경우 client와 통신을 위한 socket을 생성하여 반환한다.

  • 반환된 socket으로 client와 데이터 송수신한다.

  • ServerSocket으로는 추가 연결 대기가 가능하다.

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Exam04 {
    public static void main(String[] args) {
        int port = 12345;

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            while(!Thread.currentThread().isInterrupted()) {
                Socket socket = serverSocket.accept();
                System.out.println(socket.getInetAddress().getHostAddress() + "에 연결 완료");
                socket.getOutputStream().write("Hello!\n".getBytes());
                socket.getOutputStream().flush();
    
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();

       }
    }
}

실행결과

LISTEN 상태로 대기중

연결 시 문자 출력 후 종료

- Connection Information

ServerSocket을 이용해 특정 port를 위한 server socket을 열고, client가 접속 시 통신을 위한 socket 생성을 확인하였다.

access() 함수를 통해 받은 socket은 client에서의 socket이 연결되고, 이를 통해 client와 데이터를 주고받을 수 있다.

앞서 설명한 client socket에서 host, port 등의 정보를 확인하였다.
Server socket을 통해 client 접속 후 생성되는 socket을 통해서도 동일하게 확인할 수 있다.

- Echo Server

Client socket에서 Node-RED를 이용해 echo server를 구성하였다.
이를 server socket을 이용해 구성해 보도록 하자.

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

public class Quiz09 {
    public static void main(String[] args) {
        int port = 1234;

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            while(!Thread.currentThread().isInterrupted()) {
                Socket socket = serverSocket.accept();
                System.out.println(socket.getInetAddress().getHostAddress() + " 클라이언트가 연결 완료");

                String line;
                BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while(!(line = input.readLine()).equals("exit") ) {
                    System.out.println("터미널에서 입력한 메시지 : " + line);
                    socket.getOutputStream().write(("루프백 메시지 : "+line+"\n").getBytes());
                    socket.getOutputStream().flush();
                }
                
                System.out.println(socket.getInetAddress().getHostAddress() + " 클라이언트 연결 종료");
                socket.getOutputStream().write("서버와의 연결이 종료됩니다.\n".getBytes());
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();

       }
    }
}

실행결과

- Server/Client 프로그램 만들기

앞에서 배운 socket 프로그래밍을 이용해 간단한 프로그램을 만들어 보자.

서버 모드

package com.nhnacademy;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

public class ServerMode {
    public static void main(String[] args) {
        ServerMode serverMode = new ServerMode();

        Options options = new Options();

        Option helpOption = new Option("h", "help", false, "Help");
        Option listenOption = new Option("l", true, "server로 동작시 입력 받은 port로 listen");

        options.addOption(helpOption);
        options.addOption(listenOption);

        CommandLineParser parser = new DefaultParser();

        try {
            CommandLine commandLine = parser.parse(options, args);
            if(commandLine.hasOption(helpOption.getOpt())) {
                HelpFormatter formatter = new HelpFormatter();
                formatter.printHelp("snc [option] [hostname] [port]", options);
            }

            if(commandLine.hasOption(listenOption.getOpt())) {
                System.out.println("Server Mode 로 실행합니다.");
                String tmp_port = commandLine.getOptionValue(listenOption.getOpt());
                int tmp = Integer.parseInt(tmp_port);
                serverMode.server_Mode(tmp);
            }

        } catch (Exception e) {
            System.err.println(e);
            System.exit(0);
        }
    }

    public void server_Mode(int port) {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("서버가 " + port + " 포트에서 클라이언트의 연결을 기다리고 있습니다...");

            try (Socket clientSocket = serverSocket.accept();
                 BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
                 BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {

                System.out.println("클라이언트가 연결되었습니다.");

                // 클라이언트로부터 메시지를 받고 출력하는 스레드
                Thread inputThread = new Thread(() -> {
                    try {
                        String inputLine;
                        while ((inputLine = in.readLine()) != null) {
                            System.out.println("클라이언트가 보낸 메세지 : " + inputLine);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });

                inputThread.start();

                // 표준 입력으로부터 메시지를 받아 클라이언트에게 전송
                String userInput;
                while ((userInput = stdIn.readLine()) != null) {
                    out.write(userInput);
                    out.newLine();
                    out.flush();
                }

            } catch (Exception e) {
                System.err.println("클라이언트와의 연결에 문제가 발생했습니다: " + e.getMessage());
                e.printStackTrace();
            }
        } catch (Exception e) {
            System.err.println("서버를 생성할 수 없습니다: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

클라이언트 모드

package com.nhnacademy;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class ClientMode {
    public static void main(String[] args) {
        ClientMode clientMode = new ClientMode();

        if(args.length == 2) {
            String ser_host = args[0];
            String ser_tmp_port = args[1];
            int ser_port = Integer.parseInt(ser_tmp_port);
            clientMode.cla_mode(ser_host, ser_port);
        }
    }

    public void cla_mode(String ser_host, int ser_port) {
        try (Socket socket = new Socket(ser_host, ser_port);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
             BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {

            System.out.println(ser_host + " : " + ser_port + " 서버에 연결되었습니다.");

            // 서버로부터 메시지를 받고 출력하는 스레드
            Thread inputThread = new Thread(() -> {
                try {
                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        System.out.println("서버로부터 받은 메시지 : " + inputLine);
                    }
                } catch (Exception e) {
                    System.err.println("서버로부터 데이터를 받는 중 문제가 발생했습니다: " + e.getMessage());
                    e.printStackTrace();
                }
            });

            inputThread.start();

            // 표준 입력으로부터 메시지를 받아 서버에 전송
            String userInput;
            while ((userInput = stdIn.readLine()) != null) {
                out.write(userInput);
                out.newLine();
                out.flush();
            }

        } catch (Exception e) {
            System.err.println("서버에 연결할 수 없습니다: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

실행결과


Multi-Connection Server

Server socket은 port를 통해 대기 상태에서 client가 연결되면 통신을 위한 socket을 생성함으로써 기본 기능을 완료하고 연결된 client가 끊어진 후 accept() 함수를 통해 다시 할 수 있다.

이는 client가 연속적으로 연결될 수 있으나, 동시에 여러 client가 연결되지는 못한다.

동시에 다수의 client가 연결할 수 있도록 thread를 통해 분리해 보도록 하자.

Server socket은 대기 상태에서 client 연결이 이루어지면 이를 처리하기 위한 thread를 생성하여 생성된 socket을 넘겨주고 server socket은 다시 새로운 연결을 기다리도록 한다.

서버가 클라이언트들에게 Echo Back 실습

package com.nhnacademy;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;

public class SimpleNC {
    public static void main(String[] args) {
        Options options = new Options();

        options.addOption("l", true, "Listen");

        CommandLineParser parser = new DefaultParser();
        try {
            CommandLine commandLine = parser.parse(options, args);

            if (commandLine.hasOption("l")) {
                List<Thread> clientHandlerList = new LinkedList<>();

                ServerSocket serverSocket = new ServerSocket(1234);
                while (!Thread.currentThread().isInterrupted()) {
                    Socket socket = serverSocket.accept();
                    try {
                        Thread thread = new Thread(
                                new NetCat(socket.getInputStream(),
                                        socket.getOutputStream(),
                                        socket.getInputStream(),
                                        socket.getOutputStream()));
                        System.out.println("CLA 생성");
                        thread.start();
                        System.out.println("CLA Thread 시작");
                        clientHandlerList.add(thread);
                        System.out.println("CLA 접속됨");
                    } catch (Exception e) {
                        System.err.println(e.getMessage());
                    }
                }
                serverSocket.close();
            } else {
                try (Socket socket = new Socket("localhost", 1234)) {
                    Thread thread = new Thread(
                            new NetCat(System.in, System.out, socket.getInputStream(), socket.getOutputStream()));
                    System.out.println("Cla 생성");
                    thread.start();
                    thread.join();
                } catch (Exception e) {
                    System.err.println(e.getMessage());
                }
            }
        } catch (org.apache.commons.cli.ParseException | IOException e) {
        }
    }
}
package com.nhnacademy;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

public class NetCat implements Runnable {
    InputStream inputRemoteStream;
    OutputStream outputRemoteStream;
    InputStream inputLocalStream;
    OutputStream outputLocalStream;

    public NetCat(InputStream inputLocalStream,
            OutputStream outputLocalStream,
            InputStream inputRemoteStream,
            OutputStream outputRemoteStream) {
        this.inputLocalStream = inputLocalStream;
        this.outputLocalStream = outputLocalStream;
        this.inputRemoteStream = inputRemoteStream;
        this.outputRemoteStream = outputRemoteStream;
    }

    public void run() {
        try (BufferedReader inputLocal = new BufferedReader(new InputStreamReader(inputLocalStream));
                BufferedWriter outputLocal = new BufferedWriter(new OutputStreamWriter(outputLocalStream));
                BufferedReader inputRemote = new BufferedReader(new InputStreamReader(inputRemoteStream));
                BufferedWriter outputRemote = new BufferedWriter(new OutputStreamWriter(outputRemoteStream))) {

            Thread receiver = new Thread(() -> {
                try {
                    String line;
                    while ((line = inputRemote.readLine()) != null) {
                        outputLocal.write(line);
                        outputLocal.write("\n");
                        outputLocal.flush();
                    }
                } catch (IOException e) {
                    System.err.println(e.getMessage());
                }
            });

            Thread sender = new Thread(() -> {
                try {
                    String line;
                    while ((line = inputLocal.readLine()) != null) {
                        outputRemote.write(line);
                        outputRemote.write("\n");
                        outputRemote.flush();
                    }
                } catch (IOException e) {
                    System.err.println(e.getMessage());
                }
            });

            receiver.start();
            sender.start();

            receiver.join();
            sender.join();
        } catch (Exception e) {
            System.err.println(e.getMessage());
        } finally {
        }
    }
}

실행결과

0개의 댓글

관련 채용 정보