[Java] 네트워킹 (Networking) 2
컴퓨터끼리 통신을 할 때 쓰는 도구를 소켓이라고 한다.
소켓을 통해 진행하는 통신의 종류로는 TCP와 UDP가 있는데, 소켓 프로그래밍에 대해 알아보자.
데이터를 전송(네트워킹)은 계층적인 구조로 이루어져있다. 여기서 전송을 담당하는 계층이 있는데 이 전송 방식으로 TCP와 UDP가 있다.
TCP는 1:1 통신방식을 사용해 속도가 UDP보다 느리지만, 데이터 전송이 잘못되면 다시 요청하기 때문에 데이터의 신뢰성이 높다.
UDP 는 보내는 사람이 일방적으로 보내는 형식이라고 생각할 수 있다. 덕분에 속도도 빠르지만, 받는 데이터가 올바른 데이터인지 아닌지 확인하는 과정이 없어 데이터의 신뢰성이 좀 떨어진다. (Streaming 에서 사용함)
datagram은 데이터 단위라고 생각하면 된다. TCP는 byte단위로 데이터를 보내는데 UDP는 datagram이라는 데이터를 포함한 여러 가지 구성요소가 포함된 하나의 클래스 단위로 데이터를 보낸다.
TCP 소켓 프로그래밍
클라이언트와 서버 간의 1:1 통신이다.
서버는 서버 소켓을 만들고 서버가 어느 port를 통해서 클라이언트의 연결을 받을건지 선언한다. 여기서 어떤 port를 통해서 접속을 받을 지 결정하는 과정을 binding이라고 한다. (연관시키는 작업이라고 생각하자) IP 주소는 서버 자기 자신의 주소로 열어놓는다.
클라이언트는 소켓을 만들고 서버의 IP주소와 서버가 설정한 port를 통해서 서버와 연결한다. 이렇게 서버와 클라이언트가 소켓을 통해 연결되면 통신은 InputStream / OutputStream을 통해서 진행한다.
클라이언트가 서버에게 연결을 요청할 때 서버는 accept를 진행하는데, 이 때 서버는 클라이언트에게 새로운 소켓을 생성하고 생성한 소켓을 반환한다. 클라이언트는 자기가 설정한 소켓으로 통신하고, 서버는 accept한 순간에 반환된 소켓으로 통신을 진행한다. (1:1)
서버 코드를 살펴보자.
서버소켓을 초기화할 때 포트번호를 지정한다.
클라이언트의 연결을 받을 때 까지 계속 대기한다. (accept 함수를 사용)
클라이언트가 접속하면 소켓을 반환한다. 여기서 getInetAddrerss 로 받는 주소는 클라이언트의 주소이다.
연결되면 OutputStream을 생성한다. 쓴다는거는 어떤 내용을 써서 클라이언트에게 전송을 할 수 있다는 것.
InputStream으로는 클라이언트가 보낸 데이터를 읽을 수 있다.
DataOutputStream은 보조 스트림이다. 파일 형식에 맞게 써 주기 위해 사용한다.
UTF는 파일 형식이다. UTF-8에 한글도 있어서.. 한글도 읽어주려고 이렇게 사용함.
write로 클라이언트에게 데이터를 작성하면 클라이언트는 read를 통해 작성한 데이터를 읽을 수 있다.
클라이언트 코드를 살펴보자.
클라이언트에서는 서버 소켓을 생성할 필요 없이 바로 소켓을 생성한다.
이 때 서버가 설정한 port 와 서버의 IP주소를 인자로 넣는다.
127.0.0.1은 local host. 내 컴퓨터의 주소를 의미한다. 보통 소켓 프로그래밍을 테스트 할때 컴퓨터 하나에다가 터미널 두 개 띄우고 하니까..
나머지 내용은 서버 코드와 유사하다.
하나 보내면 하나 읽고... 하나씩 순차적으로 진행해서 데이터가 꼬일 일이 없다.
하나 읽으면 소켓을 닫아버린다. (클라이언트 소켓) 서버 소켓은 닫히지 않는다. 계속 클라이언트를 기다림.
그런데.. 무한정 기다리게 하기는 싫으면 setSoTimeout 메서드를 통해서 설정한 시간동안만 기다리게 할 수 있다.
서버가 설정한 port와 클라이언트가 사용하는 port는 다를 수 있다.
서버가 7777을 열었는데, 클라이언트는 7777로 접근하기 위해서 사용하는 port는 다른 번호일 수 있다. 다른 port 를 통해서 서버의 7777 port로 접속할 수 있다.
멀티쓰레드 이용
서버와 클라이언트가 서로 통신하는데, 클라이언트가 여러 개 있을 수 있다. 게임을 생각해보자. 게임 서버가 하나 있고 동시에 접속할 수 있는 인원이 최대 한 명이면 안된다.
멀티쓰레드를 사용하지 않으면 클라이언트 하나가 서버와 통신하는 동안 다른 클라이언트는 통신 중인 클라이언트가 통신을 종료할 때 까지 계속 기다려야 한다.
클라이언트들의 통신을 각각 멀티쓰레드로 처리해주면 두 개 이상의 클라이언트가 서버와 통신할 수 있게 된다.
쓰레드들의 동작은 동일하다.
클라이언트의 접속을 기다리고~~ 접속하면 소켓하나주고~~..
서버 소켓은 공유하지만 클라이언트가 접속했을 때 반환하는 소켓은 각각 다르다.
서버는 멀티쓰레드로 작성했지만, 클라이언트는 멀티쓰레드로 작성할 필요가 없다. 이 부분에 대해서는 조금만 생각하면 답이 나온다.
TCP는 1:1 방식으로 통신을 진행한다. 서버가 메세지를 보내면 클라이언트가 읽고 서버에게 메세지를 보내기 전에는 서버는 클라이언트에게 메세지를 보낼 수 없다. 기다리고 대기할 필요 없이 독립적으로 메세지를 주고받고 싶으면 읽는 부분과 쓰는 부분을 분리해야한다. 읽는 부분은 읽기 쓰레드를 따로 만들어서 처리하고, 쓰는 부분은 쓰는 쓰레드를 따로 만들어서 처리해야 한다.
채팅 프로그램을 구현할 때 위에서 언급한 내용이 포함된다.
채팅 서버 코드를 살펴보자.
Sender는 보내는 부분을, Receiver는 받는 부분을 쓰레드로 처리한다.
소켓은 같은 소켓을 사용함.
클라이언트 코드를 살펴보자.
'Programming Language > Java' 카테고리의 다른 글
[Java] 람다 표현식 (0) | 2023.06.09 |
---|---|
자바 예외 이해하기 (0) | 2022.09.03 |
[Java] 네트워킹 (Networking) 1 (0) | 2021.12.05 |
[Java] 입출력 (I/O) 2 (0) | 2021.11.29 |
[Java] 입출력 (I/O) 1 (0) | 2021.11.21 |
댓글
이 글 공유하기
다른 글
-
[Java] 람다 표현식
[Java] 람다 표현식
2023.06.09 -
자바 예외 이해하기
자바 예외 이해하기
2022.09.03 -
[Java] 네트워킹 (Networking) 1
[Java] 네트워킹 (Networking) 1
2021.12.05 -
[Java] 입출력 (I/O) 2
[Java] 입출력 (I/O) 2
2021.11.29