문제
- Socket 공부하면서 client -> server 단방향 통신만 있길래 그대로 응답도 보낼 수 있지 않나? 해서 server에서 OutputStream을 사용해서 client에 보내니 socket is closed 에러 발생
- 위의 이슈 해결 이후에는 sever에서 client의 데이터를 받지 못하는 문제 발생
문제 코드
클라이언트 코드
public void sendAndReceiveSocketData(String data) {
Socket socket = null;
try {
System.out.println("Client: Connecting");
socket = new Socket("127.0.0.1", 9999);
System.out.println("Client: Connect status = " + socket.isConnected());
Thread.sleep(2000);
OutputStream stream = socket.getOutputStream();
BufferedOutputStream out = new BufferedOutputStream(stream);
byte[] bytes = data.getBytes();
out.write(bytes);
out.close();
System.out.println("Client: Sent data = " + data);
System.out.println(socket.isConnected());
System.out.println("Client: receive from Server");
InputStream inputStream = socket.getInputStream();
BufferedInputStream in = new BufferedInputStream(inputStream);
byte[] readByte = new byte[256];
in.read(readByte);
System.out.println("Receive Response = " + new String(readByte).trim());
stream.close();
in.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}finally {
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
서버 코드
public void startReplyServer() {
ServerSocket server = null;
Socket client = null;
try {
server = new ServerSocket(9999);
while (true) {
System.out.println("Server:Waiting for request.");
client = server.accept();
System.out.println("Server: accepted");
InputStream stream = client.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
String data = null;
StringBuilder receivedData = new StringBuilder();
System.out.println("before while");
while (true) {
data = in.readLine();
System.out.println(data);
if(data == null) break;
receivedData.append(data);
}
System.out.println("Received data: " + receivedData);
System.out.println("Send Response");
OutputStream outputStream = client.getOutputStream();
BufferedOutputStream out = new BufferedOutputStream(outputStream);
data = "OK";
byte[] buffer = data.getBytes();
System.out.println(client.isConnected());
out.write(buffer);
out.flush();
System.out.println("send Response Success");
Thread.sleep(1000);
out.close();
outputStream.close();
in.close();
stream.close();
client.close();
if (receivedData != null && "EXIT".equals(receivedData.toString())) {
System.out.println("Stop SocketServer");
break;
}
System.out.println("--------------");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (server != null) {
try {
server.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
socket is closed라는 에러를 해결하기 위해 socket.isConnected()를 호출했는데 true가 나왔다. 하지만 out.close()를 호출하지 않으면 server에서 데이터를 받지 못하는 문제가 있었다. 이는 client에서 아직 데이터를 보내고 있다고 인식하기 때문이었다.
out.close()를 호출하면 관련된 socket도 함께 close()가 되었다. 그래서 close()를 호출하지 않고 데이터를 보낼 방법을 고민했다.
기존에 flush()를 사용하면 데이터가 전송된다고 했지만 server 측에서 데이터를 받을 수 없었다. while문에 진입했지만 in.readLine() 이후로 코드가 진행되지 않았다. in.readLine 이후 data를 출력하는 부분이 출력되지 않는 것이 이해가지 않았다.
그래서 readLine() 메소드를 찾아보았고 아래의 설명을 볼 수 있었다.
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), a carriage return followed immediately by a line feed, or by reaching the end-of-file (EOF)
"\n", "\r" 이나 파일 끝에 도달해야 종료되는데 내가 보내는 데이터에 "\n"이 포함되지 않았기 때문이다. readLine()이니 이름 그대로 "\n"이 필요한데 close()에만 집중하다 보니 당연한 것을 놓쳐버렸다..
수정한 client 코드
public void sendAndReceiveSocketData(String data) {
Socket socket = null;
try {
System.out.println("Client: Connecting");
socket = new Socket("127.0.0.1", 9999);
System.out.println("Client: Connect status = " + socket.isConnected());
Thread.sleep(2000);
OutputStream stream = socket.getOutputStream();
BufferedOutputStream out = new BufferedOutputStream(stream);
data +="\n";
byte[] bytes = data.getBytes();
out.write(bytes);
out.flush();
out.write("stop\n".getBytes());
out.flush();
...
}
...
}
그래서 위와 같이 "\n"을 추가해서 데이터를 읽을 수 있도록 하고 서버에서 데이터 전송이 완료되었다고 알리기 위해 "stop\n"을 보내서 해당 문자를 읽으면 반복문을 탈출하게 수정했다.
생각보다 많은 시간을 쏟아서 문제를 해결하니 조금 허무했다. 앞으로는 이런 실수를 줄이기 위해 내부 메소드들을 자세히 볼 필요성을 느꼈다.
'Java > Java' 카테고리의 다른 글
자바 다시 학습 하면서 알게된 것(제네릭, Collection, Map) (0) | 2023.11.13 |
---|---|
try-with-resources를 사용하면 정말 close()가 호출될까? (0) | 2023.10.14 |
[Java] 가비지 컬렉션(Garbage Collection)과 5가지 알고리즘 (0) | 2023.04.23 |
[Java] 불변 객체와 final을 사용해야 하는 이유(feat.정적 팩토리 메소드) (0) | 2023.04.23 |
Java 정리(JVM, 객체지향, 싱글톤 패턴) (0) | 2023.01.09 |