[Java_Summary] 네트워크, TCP/IP, Socket, ServerSocket, ObjectStream, transient 키워드, Serializable 인터페이스, readObject 메소드
1. TCP/IP
- Tranmission Control Protocol 두 시스템 간에 신회성 있는 데이터의 전송을 관장하는 통신 프로토콜
- Interner Protocol 통신 프로토콜
- 자신의 컴퓨터에서 자신의 IP 주소를 간단히 localhost라는 이름으로 사용 할 수 있다. localhost의 IP주소는 127.0.0.1로 정해져 있다.
- IP주소는 네트워크상에 있는 한 컴퓨터를 유일하게 식별한다.
- 한 컴퓨터 내의 여러 응용프로그램을 식별하기 위해 포트(port)를 생성하고 식별한다.
- 잘 알려진 포트(well-known ports)는 0~1023 사이에 번호를 가지므로 사용자가 작성하는 응용프로트램 포트는 이 범위를 피해서 선택하도록 한다.
- 용어
- 소켓(socket) : 통신하는 두 응용프로그램 간의 통신 링크의 각 끝단(endpoint)으로서, TCP/IP 네트워크를 이용하여 통신하도록 돕는 역할을 한다.
- 서버(server) : 정보를 제공하는 쪽
- 클라이언트(client) : 정보를 이용하는 쪽
- 서버 소켓은 서버 응용프로그램이 사용자의 접속을 기다리는(listen) 목적으로만 사용된다.
- 클라이언트 응용프로그램에서는 클라이언트 소켓을 이용하여 서버에 접속한다.
- 서버 소켓은 클라이언트가 접속해오면, 클라이언트 소켓을 추가로 만들어 상대 클라이언트와 통신하게 한다.
1.1 socket
자바에서 socket은 네트워크를 통해 두 기기 간의 통신을 가능하게 하는 엔드포인트입니다. 소켓 프로그래밍은 인터넷 또는 LAN 같은 네트워크에서 데이터를 교환하기 위한 기본적인 방법 중 하나로, TCP/IP 프로토콜을 기반으로 한 통신에서 주로 사용됩니다. 자바에서 소켓 통신을 구현하기 위해 java.net 패키지에 있는 Socket 클래스와 ServerSocket 클래스를 사용합니다.
Socket 클래스
Socket 클래스는 클라이언트 측에서 사용되며, 서버에 연결하기 위해 사용됩니다. 클라이언트는 서버의 IP 주소와 포트 번호를 사용하여 서버에 연결을 시도합니다. 연결이 성공하면, 클라이언트와 서버 간에 데이터를 송수신할 수 있는 스트림을 열 수 있습니다.
Socket 클래스의 생성자 | ||
생성자 | 설명 | |
Socket | 연결되지 않은 상태의 소켓을 생성 | |
Socket(InetAddress adress, int port) | 소켓을 생성하고, 지정된 IP주소(address)와 포트 변호(port)에서 대기하는 원격 응용프로그램의 소켓에 연결 | |
Socket(String host, int port) | 소켓을 생성하여 지정된 호스트(host)와 포트번호(port)에 연결한다. 호스트 이름이 null인 경우는 루프백(loopback)주소로 가정 |
Socket 클래스의 메소드 | |
메소드 | 설명 |
void bind(SocketAddress bindpoint) | 소켓에 로컬 IP주소와 로컬 포트 지정(결합) |
void close() | 소켓을 닫는다. |
void connect(SocketAddress endpoint) | 서버에 연결 |
InputAddress getInetAddress() | 소켓에 연결된 서버 IP주소 반환 |
InputStream getInputStream() | 소켓의 입력 스트림 반환, 이 스트림을 이용하여 소켓이 상대편으로부터 받은 데이터를 읽을 수 있음 |
InetAddress getLocalAddress() | 소켓의 로컬 주소 반환 |
int getLocalPort() | 소켓의 로켓 포트 번호 반환 |
int getPort() | 소켓에 연결된 서버의 포토 번호 반환 |
OutputStream getOutputStream() | 소켓의 출력 스트림 반환, 이 스트림에 출력하면 소켓이 서버로 데이터 전송 |
boolean isBound() | 소켓이 로컬 주소와 결합되어 있으면 true 반환 |
boolean isConnected() | 소켓이 서버에 연결되어 있으면 true 반환 |
boolean isClosed() | 소켓이 닫혀있으면 true 반환 |
void setSoTimeout(int tmeout) | 데이터 읽기 타임아웃 시간 지정. 0이면 타임아웃 해제 |
1.2 ServerSocket
ServerSocket 클래스
ServerSocket 클래스는 서버 측에서 사용되며, 특정 포트에서 클라이언트의 연결 요청을 기다립니다. 클라이언트의 연결 요청이 들어오면, 서버는 해당 요청을 수락하여 클라이언트와 통신할 수 있는 새로운 Socket 객체를 생성합니다.
소켓 프로그래밍을 통해, 클라이언트와 서버는 네트워크를 통해 서로 데이터를 주고받을 수 있으며, 다양한 네트워크 기반 애플리케이션을 개발할 수 있습니다. 자바의 Socket과 ServerSocket 클래스를 사용하면, 비교적 쉽게 네트워크 통신 기능을 구현할 수 있습니다.
ServerSocket 클래스의 생성자 | ||
생성자 | 설명 | |
ServerSocket(int port) | 지정된 포트 번호(port)와 결합된 소켓 생성 |
ServerSocket 클래스의 메소드 | |
메소드 | 설명 |
Socket accept() | 클라이언트로부터 연결 요청을 기다리다 요청이 들어오면 수락하고 클라이언트와 데이터를 주고받을 새 Socket 객체를 반환 |
void close() | 서버 소켓을 닫는다. |
InetAddress getInetAddress() | 서버 소켓의 로컬 IP 주소 반환 |
int getLocalPort() | 서버 소켓의 로켓 포트 번호 반환 |
boolean isBound() | 서버 소켓이 로컬 주소와 결합되어 있으면 true 반환 |
boolean isClosed() | 서버 소켓이 닫혀있으면 true 반환 |
void setSoTimeout(int tmeout) | accept()가 대기하는 타임아웃 시간 지정. 0이면 무한정 대기 |
1.3 Socket 예제 - 서버를 열어 문자열 주고 받기
2. ObjectStream
- Java에서 ObjectStream은 객체 직렬화와 역직렬화를 위해 사용되는 스트림의 일종입니다. 객체 직렬화란 객체의 상태를 바이트 스트림으로 변환하는 과정을 말하고, 역직렬화는 그 바이트 스트림을 다시 객체로 변환하는 과정을 말합니다. 이러한 기능은 객체를 파일에 저장하거나, 네트워크를 통해 다른 컴퓨터로 객체를 전송할 때 유용합니다. ObjectStream은 주로 ObjectInputStream과 ObjectOutputStream 클래스를 통해 구현됩니다.
- ObjectOutputStream
- ObjectOutputStream은 객체를 직렬화하여 바이트 스트림으로 출력하는 데 사용됩니다. 이 스트림을 사용하여 객체의 상태를 파일에 저장하거나, 네트워크를 통해 다른 컴퓨터로 전송할 수 있습니다.
- ObjectInputStream
- ObjectInputStream은 바이트 스트림에서 객체를 읽어 역직렬화하는 데 사용됩니다. 이 스트림을 사용하여 파일에 저장된 객체의 상태를 복원하거나, 네트워크를 통해 전송된 객체를 수신할 수 있습니다.
- 주의사항
- 역직렬화 과정에서는 클래스의 serialVersionUID가 직렬화할 때 사용된 것과 일치해야 합니다. 그렇지 않으면 InvalidClassException이 발생할 수 있습니다.
- 보안 문제: 역직렬화는 잠재적인 보안 위험을 내포하고 있습니다. 신뢰할 수 없는 소스에서 오는 데이터를 역직렬화할 때는 주의가 필요합니다. 이러한 이유로, Java 9 이상에서는 역직렬화 필터링 기능을 사용하여 특정 클래스의 역직렬화를 허용하거나 거부할 수 있습니다.
- ObjectStream을 통한 직렬화와 역직렬화 기능은 Java에서 객체의 상태를 쉽게 저장하고 전송할 수 있는 강력한 방법을 제공합니다.
2.1 transient 키워드
- 직렬화 제외: Java에서 객체를 직렬화할 때, 즉 객체의 상태를 바이트 스트림으로 변환하여 파일, 데이터베이스, 또는 네트워크를 통해 전송할 수 있게 할 때, transient로 선언된 필드는 이 과정에서 무시됩니다. 이는 보안 정보 같은 민감한 데이터를 직렬화 과정에서 제외시키거나, 필요 없는 정보를 제거하여 직렬화 데이터의 크기를 줄이기 위해 유용합니다.
- 보안과 효율성: transient 키워드를 사용함으로써 보안을 강화할 수 있으며, 네트워크를 통한 데이터 전송 시 필요하지 않은 정보를 제외시켜 효율성을 높일 수 있습니다.
- 기본값으로 초기화: 직렬화 과정에서 제외된 transient 필드는 객체가 역직렬화될 때, 즉 바이트 스트림에서 다시 객체로 변환될 때 해당 타입의 기본값으로 초기화됩니다. 예를 들어, 정수형(int) 필드는 0으로, 객체 참조는 null로 설정됩니다.
2.2 Serializable 인터페이스의 주요 포인트
- 객체의 상태 저장과 전송: Serializable 인터페이스를 구현하는 객체는 그 상태를 저장하고 나중에 다시 읽어들일 수 있도록 직렬화할 수 있습니다. 이 기능은 객체 상태의 지속성(persistence)을 관리하거나, 객체를 네트워크를 통해 전송해야 하는 분산 애플리케이션에서 중요합니다.
- 마커 인터페이스: Serializable은 메소드가 없는 마커 인터페이스입니다. 이 인터페이스를 구현한다는 것은 해당 클래스의 인스턴스가 직렬화될 수 있음을 JVM(자바 가상 머신)에 알리는 것입니다.
- UID 관리: 직렬화 과정에서 Java는 serialVersionUID라는 고유 식별자를 사용하여 클래스의 버전을 관리합니다. 클래스가 Serializable 인터페이스를 구현하고 있으며 serialVersionUID가 명시적으로 선언되어 있지 않으면, JVM은 런타임에 클래스의 해시값을 기반으로 자동으로 이 값을 생성합니다. 클래스의 구조가 변경될 경우, serialVersionUID를 관리함으로써 역직렬화 과정에서의 호환성 문제를 방지할 수 있습니다.
- 주의 사항:
- 모든 필드가 자동으로 직렬화되는 것은 아니며, transient로 표시된 필드는 직렬화에서 제외됩니다.
- 직렬화 과정에서는 객체 그래프 내의 모든 객체가 Serializable 인터페이스를 구현해야 합니다. 그렇지 않으면 NotSerializableException이 발생할 수 있습니다.
- 직렬화와 역직렬화를 할 때 클래스의 serialVersionUID가 일치해야 합니다. 그렇지 않으면 InvalidClassException이 발생할 수 있습니다.
2.3 readObject 메소드를 사용할 때는 다음 두 가지 주요 예외를 처리해야 합니다:
- ClassNotFoundException: readObject가 객체를 역직렬화할 때, 해당 객체의 클래스 타입을 찾을 수 없는 경우 발생합니다. 이는 클래스의 정의가 클래스패스에 없을 때 발생할 수 있으며, 역직렬화하려는 객체의 클래스가 JVM에서 로드되지 않았을 때 일어납니다.
IOException: 입출력 작업 중에 발생할 수 있는 예외입니다. 파일을 읽는 도중 오류가 발생하거나, 스트림이 비정상적으로 닫혔거나, 데이터를 읽는 도중 오류가 발생한 경우에 이 예외가 발생합니다.