Client에서 Server로 접속 후에 Socket
객체의 OutputStream
를 통해서 서버에게 메시지를 전달하는데 이상하게 PrintWriter
의 println 을 사용할 때는 데이터가 잘 전송됐는데 BufferedWriter
,PrintWriter
, OutputStreamWriter
의 write 메서드를 이용하면 서버에서 BufferedReader
의 readLine 메서드로 읽어지지가 않고 무한 대기 상태가 됐다.(나중에 시도해 본 결과 read(char[]) 메서드로는 읽어졌음) 심지어 예외도 일어나지 않아서 이유를 알 수 없었다.
public static void startClient(String data) {
Socket socket = null;
try {
socket = new Socket("127.0.0.1", 1234); // 소켓 서버에 접속
System.out.println("접속 성공!");
//입출력 Stream return
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
//체이닝
//PrintWriter pw = new PrintWriter(new OutputStreamWriter(out), true);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
//message 전송
bw.write(data);
bw.flush();
Thread.sleep(1000);
//server응답 메세지
System.out.println(br.readLine());
} .... catch ~
}
private static void startSocket() {
ServerSocket server = null;
Socket sc = null;
try {
ss = new ServerSocket(1234);
while (true) {
System.out.println("클라이언트 접속대기중");
//대기
sc = server.accept();
//입출력 Stream return
Thread.sleep(1000);
InputStream in = sc.getInputStream();
OutputStream out = sc.getOutputStream();
//체이닝
//PrintWriter pw = new PrintWriter(new OutputStreamWriter(out), true);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//client에서 보낸 데이터 출력
String message = null;
while (br.ready()) { // readLine은 \n \r 을 만날때 까지 무한히 실행된다.
message = br.readLine();
}
System.out.println("전송받은 데이터 : " + message);
//client에 다시 return
bw.write("return : "+message);
bw.flush();
bw.close();
br.close();
out.close();
in.close();
sc.close();
if (message != null && "exit".equals(message)) {
System.out.println("서버종료");
break;
}
}
} ...catch ~
}
처음에 봤을 때는 눈을 씻고 찾아봐도 문제는 보이지 않았다. 주석에 힌트가 나와있지만 디버깅하기 전까지는 이 문제의 답을 찾기는 쉽지 않았다.
서버의 데이터를 받는 br.readLine에서 step in을 해서 들어가 보았다. 그런데 BufferedReader
의 readLine 메 서드가 무한히 실행되고 있었던 것이었다. 이유가 뭘까 해서 종료 조건을 봤는데... '\n','\r' 이었던 것이다.
혹시나 하는 마음에 char[] 버퍼를 이용해서 BufferedReader
의 readLine이 아닌 read를 이용해 받으니 잘 실행됐다.
PrintWriter
의 println 을 사용하면 잘 됐던 이유는 println에서 '\n'을 자동으로 추가해서 데이터를 보내줬기 때문이다.
write 메 서드는 줄바꿈 문자를 보내주지 않아서 계속 무한히 read를 하고 있었던 것.. write를 쓰고 메시지를 startClient("message.\n");
이렇게 보내니 잘 작동됐다.
몇 시간 동안 고생해서 허무하긴 했지만 다음부터 이런 실수와 사용하는 라이브러리의 내부 동작 코드를 좀 더 유심히 봐야 할 필요가 있다고 생각이 들었다.
/**
* Reads a line of text. A line is considered to be terminated by any one
* of a line feed ('\n'), a carriage return ('\r'), or a carriage return
* 종료조건은 \n \r 이라고 명시. 되어있음
* followed immediately by a linefeed.
*
* @param ignoreLF If true, the next '\n' will be skipped
*
* @return A String containing the contents of the line, not including
* any line-termination characters, or null if the end of the
* stream has been reached
*
* @see java.io.LineNumberReader#readLine()
*
* @exception IOException If an I/O error occurs
*/
String readLine(boolean ignoreLF) throws IOException {
StringBuilder s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuilder(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}