java, spring

[Java] Network, TCP, Socket, Chatting, 채팅 프로그램 만들기

isaac.kim 2023. 5. 30. 18:00
728x90
반응형

[Java] Network, TCP, Socket, Chatting, 채팅 프로그램 만들기

 

Q. 인터넷 환경에서 웹 서핑, 채팅, 파일 전송 등은 어떻게 할 수 있나요?

A. 네트워크를 통해 인터넷 환경에서 위와 같은 것들을 할 수 있습니다.

 

지금 이 포스팅을 볼 수 있는 것도 네트워크 기술이 사용되었기 때문에

인터넷 브라우저를 열고 티스토리 호스팅 서버로 접속하여서 블로그를 볼 수 있게 되는 것입니다.

이번 포스팅은 Java Network에 대해서 알아보고자 합니다.

 

네트워크 개요

이미지 출처 : shlee0882.tistory.com/110

OSI(Open Systems Interconnection) 개방형 시스템 간 상호 접속

 

컴퓨터 네트워크를 공부할 때 위 OSI 7 Layer Model을 공부하게 됩니다.

이 포스팅에서는 OSI 7 Layer Model에 대해서 자세히 다루진 않으며

Java 코드로 작성할 때 알아야 할 필수 개념들에 대해서만 짚고 넘어갈 것입니다.

필요하다면 OSI 7 Layer Model에 대해서 따로 공부해 보시는 것을 추천드립니다.

 

OSI 7 Layer Model을 전부 다루진 않지만,

Java 코드를 사용해 네트워크 관련 처리를 할 때

3 Layer, 4 Layer에 대해서는 보통은 짚고 넘어갑니다.

 

3 Layer - Network Layer

4 Layer - Transport Layer

 

보통 네트워크는 다른 기기들 간의 통신을 말합니다.

 

그런데 다른 기기들과 어떻게 통신을 해야 할까요?

 

사람들이 살아가는 현실에 비유해서

통신을 사람들 간의 '소통'이라고 했을 때

어떻게 해야 다른 이와 소통할 수 있을까요?

소통하려면 만나거나 다른 어떤 매체를 통해야 합니다.

어떻게 만나서 소통할 수 있을까요?

 

집 주소, 상세 주소를 알아야 찾아가서 이야기를 하던,

우편을 보내어 메시지를 전달할 수 있습니다.

 

이때 필요한 것이 주소입니다.

EX) 서울시 OO구 OO로 OO-OO OO아파트 OOO동 OOO호

 

컴퓨터 네트워크에서 3, 4 계층이 컴퓨터나 기기의 주소를 나타냅니다.

3 Layer는 주소, 4 Layer는 상세 주소로 볼 수 있으며, 주소로 접근하면 소통할 수 있듯,

통신할 때 꼭 필요한 개념인 필수 계층입니다.

 

컴퓨터 네트워크에선 서로 간의 주소를 알아야 통신이 가능합니다.

컴퓨터 네트워크에서는 3 Layer는 IP Address(IP 주소), 4 Layer는 Port(포트)로 표현됩니다.

 

 

네트워크에서 사용되는 용어 몇 개 더 알아보겠습니다.


Port : 애플리케이션이 상호 통신을 위해 사용하는 번호, 범위는 0 ~ 65535

- 0~1023 : Well-known port numbers

- 1024~49151 : registered port numbers

- 49152~65535 : dynamic port numbers

 

Protocol : 컴퓨터 또는 단말기간의 정보 교환을 하려는 경우 원활하게 하기 위한 통신 규약

 

TCP/IP : 인터넷상에서 호스트들을 연결시키는 데 사용하는 프로토콜로 기종이 서로 다른 컴퓨터 시스템을 서로 연결해 데이터를 전송하기 위한 통신 프로토콜

- TCP는 '전화 통화'를 예시로 들 수 있습니다. 상대가 받아야 통신이 가능합니다.

 

UDP : IP를 사용하는 네트워크 내에서 컴퓨터들 간에 메시지를 교환할 때 제한된 서비스만을 제공하는 통신 프로토콜

- UDP/IP라고도 표현

- 예시로 우편과 같다고 볼 수 있습니다. 상대방이 수락하지 않더라도 전달할 수 있습니다.

 

URL : 인터넷상에 있는 각종 정보들의 위치를 나타내는 표준어

URI : 특정 자원에 접근하기 위한 형식이나 고유한 이름으로 URL보다 넓은 의미의 개념

 

Unicast : 1:1 통신, 특정한 대상 수신자에게만 보냄

Multicast : 1:다 통신, 특정한 그룹에게만 보냄

Broadcast : 1:다 통신, 동일그룹 모두에게 보냄


TCP 통신

TCP 통신은 신뢰성 프로토콜입니다.

위에서 전화통화를 예시로 들었는데,

상대가 받아야 통신이 가능하고,

끊으면 통신이 불가능합니다.

TCP 통신에서는 연결 상태가 중요합니다.

 

 

TCP에서 사용되는 Class

1. InetAddress

2. ServerSocket

3. Socket

 

각 클래스에 대해 어떻게 사용할 수 있는지 다음 내용을 확인합니다.

 

1. InetAddress

도메인으로부터 매핑되어 있는 IP주소를 관리하는 클래스

- 실제 인터넷 사이트는 IP주소가 아닌 도메인을 사용하여 관리

- IP는 매핑되어 있음

 

InetAddress 주요 메서드

1) static InetAddress getByName(String addr)

= localhost, 127.0.0.1 : 실제 자신 컴퓨터 IP주소

2) static InetAddress getAllByName(String addr)

3) static InetAddress getLocalHost()

4) String getHostAddress()

5) String getHostName()

 

코드로 실습하기

InetAddress ia = null;
InetAddress[] ias = null;

try {
    ia = InetAddress.getByName("www.naver.com");
    System.out.println("IP address : " + ia.getHostAddress());
    System.out.println("Host Name : " + ia.getHostName());
} catch (UnknownHostException e) {
    e.printStackTrace();
}
System.out.println("----------");
try {
    ias = InetAddress.getAllByName("www.google.com");
    for (int i = 0; i < ias.length; i++) {
        System.out.println("IP address : " + ias[i].getHostAddress());
        System.out.println("Host Name : " + ias[i].getHostName());
    }
} catch (UnknownHostException e) {
    e.printStackTrace();
}

실행 결과

 

 

 

2. ServerSocket

특정 컴퓨터에 TCP포트를 열어 그곳으로 요청을 받았을 때 사용하는 클래스

서버 컴퓨터에는 포트 번호를 열어 놔야 클라이언트 컴퓨터가 접속을 해서 통신을 할 수 있음

서버 컴퓨터의 포트번호를 열 때 사용하는 클래스

이미 사용 중인 포트번호일 때 IOException 발생

 

ServerSocket ss = null;
for(int i = 0; i < 65536; i++) {
    try {
        ss = new ServerSocket(i);
        ss.close();
    } catch (IOException e) {
        System.out.println("[ " + i + " ] already used.");
    }
}

 

 

3. Socket

특정 컴퓨터에 접속할 때 사용하는 클래스

- IP주소와 포트번호를 알면, 해당하는 컴퓨터와 통신을 할 수 있는데 이때 사용되는 클래스

- 서버에서는 ServerSocket을 통해 들어온 컴퓨터로 객체 발생

- 클라이언트에서는 IpAddress를 통해 관리하는 주소와 서버의 포트번호를 통해 객체 발생

 

 

 

 

TCP 통신 코드

 

Server Code

ServerSocket ss = null;
Socket soc = null;

try {
    ss = new ServerSocket(12345);
    System.out.println("server run");
    soc = ss.accept();
    System.out.println("connector : " + soc.toString());
} catch (IOException e) {
    e.printStackTrace();
}

위 코드를 실행하면 서버가 시작되고 클라이언트의 접속을 기다리게 됩니다.

클라이언트 접속받기를 기다리는 코드 : soc = ss.accept();

결과를 보더라도 connector의 정보를 출력하는 println 구문은 실행되지 않고 있는 것을 확인할 수 있습니다.

 

 

Client Code

// TCP client
InetAddress ia = null;
Socket soc = null;


try {
    ia = InetAddress.getByName("localhost");
    soc = new Socket(ia, 12345);
} catch (IOException e) {
    e.printStackTrace();
}
System.out.println("client end");

TCP 클라이언트 코드를 작성하여 TCP 서버로 연결합니다.

 

위 코드를 실행하면 TCP 서버 연결 후, 다음 구문이 출력됩니다.

 

TCP 서버에서는 soc = ss.accept() 실행 이후,

TCP 클라이언트의 접속을 기다리다가 TCP 클라이언트의 접속이 확인되자

TCP 서버에서는 접속 정보를 출력하고 프로그램이 종료됩니다.

 

 

응용 - 클라이언트에서 접속한 서버로 메시지 전달하기

 

TCP 클라이언트에서 TCP 서버로 접속할 때

메시지를 전송하고 서버에서는 받은 메시지를 출력하는 코드로 개선해 봅니다.

 

TCP Server Code

// TCP server
ServerSocket ss = null;
Socket soc = null;

try {
    ss = new ServerSocket(12345);
    System.out.println("server run");
    soc = ss.accept();
    System.out.println("connector : " + soc.toString());

    BufferedReader br = 
    new BufferedReader(
        new InputStreamReader(
            soc.getInputStream()
        )
    );

    System.out.println("recived msg : " + br.readLine());

} catch (IOException e) {
    e.printStackTrace();
}

 

TCP Client Code

InetAddress ia = null;
Socket soc = null;


try {
    ia = InetAddress.getByName("localhost");
    soc = new Socket(ia, 12345);

    String msg = "client : https://lifere.tistory.com";

    PrintWriter pw = 
    new PrintWriter(
        new BufferedWriter(
            new OutputStreamWriter(
                soc.getOutputStream()
            )
        )
    );

    pw.println(msg + "\n");
    pw.close();

} catch (IOException e) {
    e.printStackTrace();
}
System.out.println("client end");

TCP Server 출력

TCP Client 출력

 

 

응용 - 클라이언트에서 서버로 전송한 메시지를 클라이언트에서 다시 받기

'클라이언트에서 서버로 전송한 메시지를 클라이언트에서 다시 받기'

와 같은 것을 에코 서버라고 합니다.

 

TCP Server Code

// TCP server
ServerSocket ss = null;
Socket soc = null;

try {
    ss = new ServerSocket(12345);
    System.out.println("server run");
    soc = ss.accept();
    System.out.println("connector : " + soc.toString());

    BufferedReader br = 
    new BufferedReader(
        new InputStreamReader(
            soc.getInputStream()
        )
    );

    String msg = br.readLine();
    System.out.println("recived msg : " + msg);

    PrintWriter pw = 
    new PrintWriter(
        new BufferedWriter(
            new OutputStreamWriter(
                soc.getOutputStream()
            )
        )
    );

    pw.println(msg + "\n");
    pw.close();
} catch (IOException e) {
    e.printStackTrace();
}

 

TCP Client Code

// TCP client
InetAddress ia = null;
Socket soc = null;


try {
    ia = InetAddress.getByName("localhost");
    soc = new Socket(ia, 12345);

    String msg = "client : https://lifere.tistory.com";

    PrintWriter pw = 
    new PrintWriter(
        new BufferedWriter(
            new OutputStreamWriter(
                soc.getOutputStream()
            )
        )
    );

    pw.println(msg + "\n");

    // pw.close();
    pw.flush();

    BufferedReader br = 
    new BufferedReader(
        new InputStreamReader(
            soc.getInputStream()
        )
    );

    System.out.println("from server msg : " + br.readLine());

} catch (IOException e) {
    e.printStackTrace();
}
System.out.println("client end");

TCP Server, TCP Client 실행 결과

서버 출력
클라이언트 출력

 

처음 작성한 코드에서 조금씩 개선한 코드이므로

별도의 추가 설명 없어도 무리 없이 이해할 수 있을 것이라 생각합니다.

 

반응형

Chatting

위 코드를 응용해서 채팅 프로그램으로 개선합니다.

 

ChatServer.java

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ChatServer extends Thread{

    ServerSocket ss = null;
    Socket soc = null;

    PrintWriter pw = null;
    BufferedReader br = null;
    Scanner sc = null;
    
    public ChatServer() {
        try {
            ss = new ServerSocket(12345);
            System.out.println("server run... ");
            
            soc = ss.accept();
            System.out.println("connection - client");
            
            this.start();
            System.out.println("Server Thread start");
            System.out.println("--------------------");

            sc = new Scanner(System.in);
            pw = 
            new PrintWriter(
                new BufferedWriter(
                    new OutputStreamWriter(
                        soc.getOutputStream()
                    )
                )
            );

            while(true) {
                System.out.print("server : ");
                String msg = sc.nextLine();
                pw.println(msg);
                pw.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            br = 
            new BufferedReader(
                new InputStreamReader(
                    soc.getInputStream()
                )
            );

            while(true) {
                String cliMsg = br.readLine();
                System.out.println("client message : " + cliMsg);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        new ChatServer();
    }
}

 

ChatClient.java

public class ChatClient extends Thread {

    InetAddress ia = null;
    Socket soc = null;

    PrintWriter pw = null;
    BufferedReader br = null;
    Scanner sc = null;

    public ChatClient() {
        try {
            ia = InetAddress.getByName("localhost");
            soc = new Socket(ia, 12345);

            this.start();
            System.out.println("Client Thead start");
            System.out.println("--------------------");

            sc = new Scanner(System.in);
            pw = 
            new PrintWriter(
                new BufferedWriter(
                    new OutputStreamWriter(
                        soc.getOutputStream()
                    )
                )
            );

            while(true) {
                System.out.print("client : ");
                String msg = sc.nextLine();
                pw.println(msg);
                pw.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            br = 
            new BufferedReader(
                new InputStreamReader(
                    soc.getInputStream()
                )
            );

            while(true) {
                String serverMsg = br.readLine();
                System.out.println("server message : " + serverMsg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    }


    public static void main(String[] args) {
        new ChatClient();
    }
}

 

 

ChatServer, ChatClient 실행 결과

 

UI 작업은 하지 않아서 매끄러운 채팅 UI/UX는 아니지만,

Server와 Client가 메시지를 주고받을 수 있는 간단한 채팅 프로그램을 만들어 보았습니다.

 


 

Java Network와 채팅 프로그램 만들기 등을 통해 Java Network와 친해졌을 것이라 생각합니다.

도움이 되셨다면 Google Adsense 광고 클릭 한 번 부탁드리겠습니다! : )

 

Java Network Repository 보러 가기

 

 

728x90
반응형