이전 포스팅인 단방향 소켓 프로그래밍에 이어서 이번 포스팅은 양방향 통신을 주제로 설명해보려고 합니다.
이전 포스팅에서 정리했던 용어들은 알고있다고 가정하에 진행하도록 하겠습니다.
[ 양방향 통신 ]
- 서버 측에서는 ServerSocket을 생성하고 accept() 메서드를 호출함으로써 클라이언트의 접속을 대기한다.
- 클라이언트 측에서는 서버에 접속을 함으로써 서버와의 통신을 위한 Socket을 생성한다.
- 마찬가지로 서버 측에서 클라이언트 접속이 이루어지면 해당 클라이언트와 통신 할 수 있는 Socket을 반환받는다.
- 클라이언트와 서버는 생성된 소켓을 통하여 각각 상대에게 데이터를 내보내기 위한 출력 스트림(OutputStream)과 데이터를 읽어들이기 위한 입력 스트림(InputStream)을 생성한다.
- 생성된 스트림을 통하여 서버/클라이언트 서로간에 데이터를 송수신한다.
- 통신이 끝나면 클라이언트와 서버측에서 각각 socket.close()를 해줌으로써 통신을 종료하게 된다.
[ 간단한 문자열 주고 받기 ]
소스코드를 작성한 뒤, 분석하면서 양방향 통신에 대해 더 알아보도록 하겠습니다.
[ 클라이언트 측 소스코드 ]
package testPjt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class InputOuputClient {
public static void main(String[] args) {
Socket socket = null;
OutputStream outputStream = null;
DataOutputStream dataOutputStream = null;
InputStream inputStream = null;
DataInputStream dataInputStream = null;
Scanner scanner = null;
try {
socket = new Socket("localhost", 9000);
System.out.println("서버 연결 완료!");
outputStream = socket.getOutputStream();
dataOutputStream = new DataOutputStream(outputStream);
inputStream = socket.getInputStream();
dataInputStream = new DataInputStream(inputStream);
scanner = new Scanner(System.in);
while (true) {
System.out.println("↓ 메시지를 입력해주세요 ↓");
String outMessage = scanner.nextLine();
dataOutputStream.writeUTF(outMessage); // 서버 측으로 데이터 전송
dataOutputStream.flush(); // 완전히 비우기 위함
String receviedMessage = dataInputStream.readUTF();
System.out.println("받은 메세지 : " + receviedMessage);
if (outMessage.equals("stop")) break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (dataOutputStream != null) dataOutputStream.close();
if (outputStream != null) outputStream.close();
if (dataInputStream != null) dataInputStream.close();
if (inputStream != null) inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
양방향 통신을 위해 출력스트림(OutputStream)과 입력스트림(InputStream)의 인스턴스 변수를 선언하고 문자열을 조금 더 쉽게 주고받기 위해 DataOutputStream과 DataInputStream 또한 인스턴스 변수를 선언하자.
그리고 클라이언트 측에서 메세지를 보내야하니 메세지를 입력받을 때 사용하는 scanner 인스턴스 변수도 선언하자.
socket 변수에 주소와 포트번호를 지정해준다.
getInputStream() 메서드와 getOutputStream() 메서드를 사용한다.
dataOutputStream과 dataInputStream 객체를 생성할 때는 각 클래스의 생성자 매개변수로 socket으로부터 얻은 스트림을 할당한다.
반환형 | 메서드 | 설명 |
InputStream | getInputStream() | 소켓 객체로부터 입력할 수 있는 InputStream 객체를 반환한다. |
OutputStream | getOutputStream() | 소켓에 대한 출력 스트림 반환 |
stop이라고 메세지를 작성하지 않는 한, 계속 메세지를 주고받을 것이기 때문에 while문을 걸어준다.
scanner로 한 줄씩 입력받기 때문에 nextLine 메서드를 사용한다.
서버 측으로 데이터를 전송하기 위해서 writeUTF() 메서드를 사용한다. 그리고 전송했던 변수를 완전히 비우기 위해서 flush() 메서드를 사용해준다.
receviedMessage를 선언한 이유는 '성공적으로 메세지가 전송됐다'는 확인 메세지를 다시 받기 위해서이다. 그래서 readUTF를 사용한 것.
마지막 줄의 if문은 stop 메세지를 보내면 양방향간 소통이 종료된다.
이 부분은 양방향간 소통이 끝나면 닫아줘야하기 때문에 close 메서드를 사용한 부분이다.
[ 서버 측 소스코드 ]
package testPjt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class InputOutputServer {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
OutputStream outputStream = null;
DataOutputStream dataOutputStream = null;
InputStream inputStream = null;
DataInputStream dataInputStream = null;
try {
serverSocket = new ServerSocket(9000);
System.out.println("클라이언트로부터 데이터 전송받을 준비 완료");
socket = serverSocket.accept();
System.out.println("클라이언트 연결 완료");
System.out.println("socket : " + socket);
inputStream = socket.getInputStream();
dataInputStream = new DataInputStream(inputStream);
outputStream = socket.getOutputStream();
dataOutputStream = new DataOutputStream(outputStream);
while (true) {
String clientMessage = dataInputStream.readUTF();
System.out.println("clientMessage : " + clientMessage);
dataOutputStream.writeUTF("메세지 전송 완료");
dataOutputStream.flush();
if (clientMessage.equals("stop")) break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (dataOutputStream != null) dataOutputStream.close();
if (outputStream != null) outputStream.close();
if (dataInputStream != null) dataInputStream.close();
if (inputStream != null) inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
클라이언트 측과 동일하게 인스턴스 변수들을 선언해주고.
서버 측이기 때문에 ServerSocket 객체를 추가로 생성해준다.
그리고 클라이언트로가 들어올 때까지 기다렸다가 들어오면 accept()메서드가 받고 socket 변수에 저장한다.
클라이언트로부터 받은 메세지를 출력하기 위해 readUTF() 메서드를 사용한다.
그리고 정상적으로 메세지를 받았다는 메세지를 클라이언트에 다시 보내주기 위해 writeUTF() 메서드로 보내고 flush 처리를 해준다.
만약에 클라이언트에서 보낸 메세지가 stop이라면 이러한 행위를 멈추게 된다.
클라이언트와 마찬가지로 동일한 예외 처리를 해준다.
[ 양방향 관계 도식화 ]
'Programming > Java' 카테고리의 다른 글
[Java] Log4j에 대해 알아보자 (0) | 2019.11.11 |
---|---|
[JAVA] 날짜와 시간 다루기(java.time) (0) | 2019.11.09 |
[JAVA] TCP 통신 소켓 프로그래밍(단방향 통신) (0) | 2019.08.02 |
[JAVA] public class & class 차이 (5) | 2019.04.02 |
[JAVA] 생성자(Contructor)에 대해 알아보자 (0) | 2019.03.30 |