✔️이 글은 [자바의 신 - 이상민 지음] 도서를 바탕으로 정리한 글입니다.
네트워크 프로그래밍이란?
바로 옆에 있는 장비와 데이터를 주고 받는 작업을 보통 네트워킹(Networking)이라 한다. 이런 네트워킹은 다음과 같이 레이어로 구분되어 있다.
자바에서 활용하는 대표적인 레이어에는
- 애플리케이션 레이어(HTTP, ftp, telnet...)
- 트랜스포트 레이어(TCP, UDP, ...)
- 네트워크 레이어(IP, ...)
- 링크 레이어(device driver, ...) 가 있다.
애플리케이션 레이어 중 가장 대표적인 HTTP(Hypertext Transfer Protocol), FTP(File Transfer Protocol), Telnet들은 모두 TCP(Transmission Control Protocol) 통신을 한다. 어플리케이션 레이어에서 자바로 프로그래밍만 하면 트랜스포트 레이어에서의 처리는 자바가 알아서 해준다.
TCP 통신은 가장 대표적인 통신 방법으로 "연결 기반 프로토콜"이라 불린다. TCP는 상대방이 데이터를 받았는지 확실하게 보장해준다.
트랜스포트 레이어에는 UDP(User Datagram Protocol)이 있는데 TCP와 다른 점 중 하나는 다른 장비가 데이터를 제대로 받았는지에 대한 보장이 안된다는 것이다. TCP는 데이터 전송이 확실하다는 보장은 되지만 내부적으로 처리하는 절차가 매우 복잡해 느리고 비싸지만, UDP는 데이터 전송은 보장 못해줘도 싸고 빠르게 전송된다는 장점이 있다.
TCP/IP에서의 포트(Port)는 클라이언트 프로그램이 네트워크 상의 특정 프로그램을 지정할 때 사용한다. 어느 서버에 접속해야 하는지 포트번호를 통해 지정해준다. 웹 서버는 80번이라는 포트 번호를 가지고, 웹으로 SSL 통신을 하려면 443 포트를 사용해야 한다. 0~1023번까지는 well-known port로 정해진 용도로 사용해야 한다. 포트는 16비트로 65535까지 사용할 수 있어 1024개를 제외한 나머지 값을 사용자 임의로 사용하면 된다.
소켓이란 네트워크 상에서 돌아가는 두 프로그램 간 양방향 통신을 위한 연결부(종착점,Endpoint)로 포트 번호에 바인딩 되어 TCP 레이어에서 데이터가 전달되어야 하는 애플리케이션을 식별할 수 있게 한다. 엔드 포인트는 IP 주소와 port 번호의 조합으로 모든 TCP 연결은 2개의 엔드 포인트로 유일하게 식별된다.
소켓 통신을 하기 위해서 알아야 하는 Socket 클래스
TCP 통신을 자바에서 수행하려면 Socket 클래스를 사용하면 된다. java.net 패키지에 관련된 클래스들이 선언되어 있다.
Socket 클래스는 데이터를 보내는 쪽(클라이언트)에서 객체를 생성하여 사용한다. 데이터를 받는 쪽(서버)에서 클라의 요청을 받으면 요청에 대한 Socket객체를 생성하여 데이터를 처리한다. Socket 클래스는 클라와 서버 모두 원격 연결 상태를 보관하고 있다.
서버에서 데이터를 받을 땐 ServerSocket이라는 클래스를 사용한다. 이 클래스의 메소드에서 클라의 요청이 오면, 서버의 Socket 클래스를 생성해서 전달해준다.
ServerSocket 클래스 생성자
- ServerSocket() : 서버 소켓 객체 생성
- ServerSocket(int port) : 지정한 port를 사용하는 서버 소켓 생성
- ServerSocket(int port, int backlog) : 지정된 포트와 backlog 개수를 갖는 소켓 생성
- ServerSocket(int port, int backlog, InetAddress bindAddr) : 지정된 포트와 backlog 개수를 갖는 소켓를 생성하며, binAddr에 있는 주소에서의 접근만 허용
backlog는 ServerSocket 객체가 연결 요청을 처리하지 못하고 대기하는 경우가 있는데 그 때의 최대 대기 개수를 의미한다.
backlog를 지정해주지 않으면 50개로 자동 지정해준다.
매개변수가 없는 ServerSocket 생성자는 객체 생성후 별도로 연결 작업을 해야 대기가 가능하고, 나머지는 자동으로 생성되자마자 연결 대기 상태가 된다.
- accept() : 새로운 소켓 연결을 기다리고, 연결이 되면 Socket 객체를 리턴
- close() : 소켓 연결을 종료, 해당 메소드를 호출해야 서버나 PC에서 다른 프로그램이 사용할 수 있어짐
데이터를 받는 서버에서는 클라에서 접속을 하면 Socket 객체를 생성하지만, 클라에서는 Socket 객체를 직접 생성해줘야 한다.
Socket 클래스 생성자
- Socket() : 소켓 객체만 생성
- Socket(Proxy proxy) : 프록시 관련 설정과 함께 소켓 객체만 생성
- Socket(SocketImpl impl) : 사용자가 지정한 SocketImpl 객체를 사용해 소켓 객체만 생성
- Socket(InetAddress address, int port) : 소켓 객체 생성 후 address와 port를 사용하는 서버에 연결
- Socket(InetAddress address, int port, InetAddress localAddr, int localPort) : 소켓 객체 생성 후 address와 port를 사용하는 서버에 연결, 지정한 localAddr와 localPort에 접속
- Socket(String host, int port) : 소켓 객체 생성 후 host와 port를 사용하는 서버에 연결
- Socket(String host, int port, InetAddress localAddr, int localPort) : 소켓 객체 생성 후 host와 port를 사용하는 서버에 연결하며, 지정된 localAddr와 localPort에 접속
밑에서 두번째에 있는 생성자 외의 대부분의 생성자들은 별도의 용도가 있는 Socket 객체를 생성하는 것이라고 생각하면 된다.
맨 위 3개 생성자를 제외한 나머지는 모두 객체 생성과 함께 지정된 서버에 접속까지 한다.
Socket 클래스도 작업이 끝나면 close() 메소드로 소켓을 닫아야 한다.
소켓 연결에 문제가 있을 경우 끊어주는 Timeout관련 메소드는 운영용 시스템 개발시 중요하기 떄문에 살펴보는 것을 추천한다.
간단하게 소켓 통신을 해보자
서버(소켓 대기)
1. 포트 번호를 지정해 ServerSocket 객체(server) 생성
2. server.accept() 메소드를 호출해 다른 원격 호출을 대기하는 상태로 만들어주고 연결이 완료돼 Socket 객체를 리턴하면 client라는 변수에 할당
3. client.getInputStream()메소드를 호출해 데이터를 받아옴
4. 모든 데이터 처리가 끝난 후 Socket 사용 종료를 알리기 위해 close() 메소드 호출
5. 더 이상 소켓 수신할 필요가 없을 때 server.close() 메소드 호출
클라이언트(데이터 전송)
1. IP주소와 port 번호를 지정한 Socket 객체(socket) 생성
2. 데이터 전송을 위해 socket.getOutputStream() 메소드를 호출해 OutputStream 객체(stream) 생성
3. 데이터 전달 후 close() 메소드로 소켓 연결을 닫아줌
소켓 통신시 발생할 수 있는 예외
- java.net.BindException : Address already in use 서버를 띄워놓고 또 띄웠을 때 발생한다. 이미 지정된 port 번호를 사용하고 있기 때문에 동일한 port번호 사용이 불가능
- java.net.ConnectException : Connection refused 서버를 띄워 놓지 않고 클라 프로그램만 수행했을 때 발생
UDP 통신을 위해서 알아야 하는 Datagram 관련 클래스
UDP는 TCP와 달리 하나의 클래스 DatagramSocket에서 보내는 역할과 받는 역할을 모두 수행한다. 또 TCP는 스트림 객체를 얻어 데이터를 주고받지만, UDP에선 스트림을 사용하지 않고 DatagramPacket 클래스를 이용한다.
DatagramSocket 클래스의 생성자
- DatagramSocket() : 소켓 객체 생성 후 사용 가능한 포트로 대기
- DatagramSocket(DatagramSocketImpl impl) : 사용자가 지정한 객체를 사용해 소켓 객체만 생성
- DatagramSocket(int port) : 소켓 객체 생성 후 지정된 port로 대기
- DatagramSocket(int port, InetAddress address) : 소켓 객체 생성 후 address와 port를 사용하는 서버에 연결
- DatagramSocket(SocketAddress address) : 소켓 객체 생성 후 address에 지정된 서버로 연결
DatagramSocket 메소드
- receive(DatagramPacket packet) : 메소드 호출시 요청을 대기하고, 데이터를 받으면 packet 객체에 데이터 저장
- send(DatagramPacket packet) : packet 객체에 있는 데이터 전송
- close() : 더이상 사용하지 않을 때 호출
DatagramPacket 클래스의 생성자 중 단 하나만 데이터를 받기 위한 생성자고, 나머지는 데이터를 전송하기 위한 생성자이다.
DatagramPacket 클래스의 생성자
- DatagramPacket(byte[] buf, int length) : length의 크기를 갖는 데이터를 받기 위한 객체 생성
- DatagramPacket(byte[] buf, int length, InetAddress address, int port) : 지정된 address와 port로 데이터를 전송하기 위한 객체 생성
- DatagramPacket(byte[] buf, int offset, int length) : 버퍼의 offset이 할당되어 있는 데이터를 전송하기 위한 객체 생성
- DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) : 버퍼의 offset이 할당되어 있고, 지정된 address와 port로 데이터를 전송하기 위한 객체 생성
- DatagramPacket(byte[] buf, int offset, int lneght, SocketAddress address) : 버퍼의 offset이 할당되어 있고, 지정된 소켓 address로 데이터를 전송하기 위한 객체 생성
- DatagramPacket(byte[] buf, int length, SocketAddress address) : 지정된 소켓 address로 데이터를 전송하기 위한 객체 생성
byte는 전송되는 데이터고, offset은 전송되는 byte 배열의 첫 위치이다. 위치는 0부터 시작한다. length는 데이터의 크기를 의미한데 byte 배열의 크기보다 크면 java.lang.IllegalArgumentException 예외가 발생한다.
DatagramPacket의 메소드
- getData() : byte[]로 전송받은 데이터 리턴
- getLength() : 전송 받은 데이터 길이 int로 리턴
간단하게 UDP 통신을 해보자
서버
1. port 번호를 지정한 DatagramSocket 객체(server) 생성
2. 데이터를 받기 위한 DatagramPacket 객체(packet) 생성
3. server.receive(packet) 메소드로 데이터를 받기 위해 대기하다가, 데이터가 넘어오면 packet 객체에 데이터 담음
4. 전송받은 데이터의 크기를 packet.getLength()로 확인
5. byte 배열로 되어 있는 데이터를 String 문자열로 변경 -> 해당 문자열을 출력해보면 받은 데이터를 알 수 있음
클라이언트
1. DatagramSocket 객체(client) 생성
2. InetAddress 객체를 사용해 데이터를 받을 서버의 IP를 설정
3. 데이터 전송을 위한 DatagramPacket 객체(packet) 생성, 생성자 매개변수로 서버의 주소와 port번호 등을 지정해주면 전송하기 위한 객체가 됨
4. client.send(packet)을 이용해 데이터를 전송
작업이 끝난 서버와 클라이언트 모두 close() 메소드 사용해 소켓 연결 종료를 해줘야 한다.
UDP 통신시에는 서버에서 데이터 받을 준비가 되어있지 않더라도 클라에서 아무 오류를 내지 않고 그냥 수행한다.
TCP에서는 서버에 접속하지 못하면 ConnectException 예외가 발생한다.
자바에서 웹 페이지 요청을 하려면 어떻게 해야 하지?
자바에서 인터넷을 통해 웹페이지를 요청할 떄는 URL이라는 클래스를 사용하면 된다.
내가 운영하는 시스템 내에서 웹 페이지 요청시에는 상세한 설정을 못하는 URL클래스를 사용하기 보다는 Apache의 Http Components를 많이 사용한다.
정리해 봅시다
1. TCP 통신과 UDP 통신의 차이는?
TCP는 확실한 연결과 데이터 전송을 보장하지만, UDP는 그렇지 않다.
2. 네트워크 통신시 포트 번호를 지정하는 이유는?
서버 내에서 여러가지 프로그램에서 서로 다른 데이터를 처리해주기 위해서 사용한다.
3. ServerSocket 클래스의 용도는?
TCP 통신시 서버에서 데이터를 받을 때 사용한다.
4. ServerSocket 클래스의 accept() 메소드의 용도는?
새로운 소켓 연결을 기다리고, 연결이 되면 Socket 객체를 리턴한다.
5. Socket 클래스의 용도는?
TCP로 받은 데이터를 처리하거나, 데이터 전송할 때 사용한다.
6. DatagramSockeet 클래스의 용도는?
UDP 통신을 하기 위해서 사용된다.
7. DatagramPacket 클래스의 용도는?
UDP로 데이터를 받거나 보낼때 사용한다.
'도서 > 자바의 신' 카테고리의 다른 글
[도서/자바의 신] #31 Java 7에 추가된 것들에는? (0) | 2023.01.02 |
---|---|
[도서/자바의 신] #30 Java 7에서 달라진 것들에는? (0) | 2023.01.02 |
[도서/자바의 신] #27 Serialiable과 NIO도 살펴봅시다 (1) | 2023.01.01 |
[도서/자바의 신] #26 파일에 있는 것을 읽고 쓰려면 아이오를 알아야죠 (1) | 2023.01.01 |
[도서/자바의 신] #25 쓰레드는 개발자라면 알아두는 것이 좋아요 (1) | 2022.12.31 |