
자바를 공부하다 보면 네트워크 통신이라는 개념을 만나게 된다.
이번 실습에서는 서버(Server)와 클라이언트(Client)가 서로 메시지를 주고받는 간단한 채팅 프로그램을 구현해보았다.
핵심은 소켓(Socket) 이라는 개념이다.
소켓은 네트워크 통신을 위한 연결 통로라고 볼 수 있다.
쉽게 말하면 다음과 같은 구조다.
클라이언트 <---- Socket ----> 서버
즉 소켓은 네트워크 통신의 출입구라고 생각하면 이해하기 쉽다.
먼저 서버 코드를 살펴보자.
package scoketPractice;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Server {
public static void main(String[] args) {
String clientMsg = null, serverMsg = null;
System.out.println("클라이언트로 부터 받을 준비");
try(
ServerSocket serverSocket = new ServerSocket(1100);
Socket socket = serverSocket.accept();
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter =
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner sc = new Scanner(System.in);
){
System.out.println("클라이언트가 연결 되었습니다.");
while(true) {
clientMsg = bufferedReader.readLine();
System.out.println("[클라이언트]: " + clientMsg);
System.out.println("클라이언트로 보낼 답변을 입력하시오...");
serverMsg = sc.nextLine();
bufferedWriter.write(serverMsg + "\n");
bufferedWriter.flush();
System.out.println("[서버]: " + serverMsg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
서버의 흐름은 다음과 같다.
ServerSocket serverSocket = new ServerSocket(1100);
1100번 포트를 열고 클라이언트 연결을 기다린다.
Socket socket = serverSocket.accept();
클라이언트가 접속하면
Socket 객체를 통해 통신이 시작된다.
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter =
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
InputStream → 데이터를 받는 통로OutputStream → 데이터를 보내는 통로clientMsg = bufferedReader.readLine();
클라이언트 메시지를 받고
bufferedWriter.write(serverMsg + "\n");
bufferedWriter.flush();
서버 메시지를 다시 보내준다.
클라이언트 코드는 다음과 같다.
package scoketPractice;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
String clientMsg = null, serverMsg = null;
int port = 1100;
String ip = "192.168.215.105";
System.out.println("서버에 연결 준비");
try(
Socket socket = new Socket(ip, port);
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter =
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner sc = new Scanner(System.in);
){
System.out.println("서버에 연결 완료");
while(true) {
System.out.println("서버에 보낼 메세지를 입력하세요");
clientMsg = sc.nextLine();
bufferedWriter.write(clientMsg + "\n");
bufferedWriter.flush();
System.out.println("[클라이언트]: " + clientMsg);
serverMsg = bufferedReader.readLine();
System.out.println("[서버]: " + serverMsg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
클라이언트는 서버와 달리 연결을 기다리는 것이 아니라 연결을 요청한다.
Socket socket = new Socket(ip, port);
이 두 정보를 이용해서 서버에 접속한다.
연결이 성공하면 이후에는 서버와 동일하게 스트림을 이용해서 데이터를 주고받는다.
서버와 클라이언트를 실행하면 다음과 같은 대화가 가능하다.
클라이언트: 안녕하세요
서버: 반갑습니다
클라이언트: 오늘 날씨가 좋네요
서버: 맞아요
이렇게 양방향 통신이 가능하다.
이번 실습에서 가장 중요한 개념은 다음이다.
네트워크 통신을 위한 연결 통로
서버가 클라이언트 연결을 기다리기 위한 객체
서버와 클라이언트 사이에서
실제 데이터 통신을 담당하는 객체
데이터를 주고받기 위한 통로
이번 실습을 통해 자바에서 네트워크 통신의 기본 구조를 이해할 수 있었다.
정리하면 다음과 같다.
ServerSocket → 연결 대기
Socket → 실제 통신
Stream → 데이터 송수신
지금 구현한 코드는 1:1 채팅 수준의 간단한 예제이지만,
여기에 Thread를 추가하면 여러 명이 동시에 접속하는 채팅 서버도 만들 수 있다.
앞으로는 멀티스레드를 활용해서
여러 클라이언트를 동시에 처리하는 채팅 서버도 구현해보고 싶다.