책 '자바 네트워크 프로그래밍' 보고 정리했습니다.
- 서버
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class ChatServer {
public ChatServer() {
System.out.println("Chat Server started");
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 서버 소켓 채널 열기
ServerSocket socket = serverSocketChannel.socket(); // 내부 소켓 얻기
socket.bind(new InetSocketAddress(5000)); // 포트번호로 바인딩
boolean running = true;
while (running) {
System.out.println("Waiting for request ..."); // 요청 기다리기
SocketChannel socketChannel = serverSocketChannel.accept(); // 블로킹, 소켓에 대한 접속을 받아들임
System.out.println("Connected to Client"); // 연결 완료
String message;
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("> ");
message = scanner.nextLine(); // 메세지 입력받기
if (message.equalsIgnoreCase("quit")) { // 대소문자 구분없이 quit 입력 시 종료하기
HelperMethods.sendMessage(socketChannel, "Server terminating"); // 종료
running = false;
break;
} else {
HelperMethods.sendMessage(socketChannel, message); // 메세지 보내기
System.out.println("Waiting for message from client ...");
// 메세지 받을 때까지 기다리기, 받으면 출력
System.out.println("Message: " + HelperMethods.receiveMessage(socketChannel));
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ChatServer();
}
}
- 클라이언트
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class ChatClient {
public ChatClient(){
SocketAddress address = new InetSocketAddress("127.0.0.1", 5000); // 소켓 생성
try (SocketChannel socketChannel = SocketChannel.open(address)){ // 접속하기
System.out.println("Connected to Chat Server"); // 연결이 됨
String message;
Scanner scanner = new Scanner(System.in);
while(true){
System.out.println("Waiting for message from the server ..."); // 하나를 받을 때까지 기다리기
System.out.println("Message: " + HelperMethods.receiveMessage(socketChannel)); // 받을 때까지 블로킹, 받으면 출력
System.out.print("> ");
message = scanner.nextLine(); // 입력하기
if(message.equalsIgnoreCase("quit")){ // 대소문자 구분 없이 quit 입력 시 종료
HelperMethods.sendMessage(socketChannel, message);
break;
}
HelperMethods.sendMessage(socketChannel, message); // 보내기
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ChatClient();
}
}
- HelperMethods
서버와 클라이언트 간의 메세지를 주고 받을 때, 고정 길이 or 가변 길이 메소드를 실행하는 HelperMethods 입니다.
고정 길이 메소드를 사용하면, message 가 정해놓은 고정 길이를 초과할 때, 오류가 발생합니다.
가변 길이 메소드를 사용하면, 이러한 문제를 해결할 수 있습니다.
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class HelperMethods {
// buffer.flip() 은 position(현재위치)를 limit(어디까지 사용할 지)로 설정하고, position을 0으로 바꾼다.
// 그래서 처음부터 읽으려고 할 때, 사용한다.
// 고정 길이 메소드
public static void sendFixedLengthMessage(SocketChannel socketChannel, String message){
try {
ByteBuffer buffer = ByteBuffer.allocate(64); // 버퍼 크기를 64로 지정한다.
buffer.put(message.getBytes()); // 메세지 길이만큼 저장한다.
buffer.flip(); // 버퍼를 읽을 준비를 한다.
while(buffer.hasRemaining()){ // 읽을 것이 있으면,
socketChannel.write(buffer); // 쓴다.
}
System.out.println("Sent: " + message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String receiveFixedLengthMessage(SocketChannel socketChannel){
String message = "";
try {
ByteBuffer byteBuffer = ByteBuffer.allocate(64); // 버퍼 크기를 64로 지정한다.
socketChannel.read(byteBuffer); // 읽는다.
byteBuffer.flip(); // 버퍼를 읽을 준비를 한다.
while(byteBuffer.hasRemaining()){ // 읽을 것이 있으면,
message += (char) byteBuffer.get(); // 하나씩 추가해준다.
}
} catch (IOException e) {
e.printStackTrace();
}
return message; // 하나하나씩 모아진 메세지를 return 해준다.
}
// 가변 길이 메시지 처리
public static void sendMessage(SocketChannel socketChannel, String message){
try {
ByteBuffer buffer = ByteBuffer.allocate(message.length() + 1); // 종료 문자를 넣기 위해 +1 을 한다.
buffer.put(message.getBytes()); // 메세지를 넣는다.
buffer.put((byte)0x00); // 메세지 끝에 종료 문자를 넣는다.
buffer.flip(); // 버퍼를 읽을 준비를 한다.
while(buffer.hasRemaining()){ // 읽을 것이 있으면
socketChannel.write(buffer); // 쓴다.
}
System.out.println("Sent: " + message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String receiveMessage(SocketChannel socketChannel){
try {
ByteBuffer byteBuffer = ByteBuffer.allocate(16); // 버퍼 크기를 16 으로 지정한다.
String message = "";
while(socketChannel.read(byteBuffer) > 0){ // 더 읽을 것이 있다면, (16씩 계속 읽는 중)
char byteRead = 0x00; // 종료 문자를 설정한다.
byteBuffer.flip(); // 버퍼를 읽을 준비를 한다.
while(byteBuffer.hasRemaining()){ // 읽어온 16 중에서 읽을 것이 있다면,
byteRead = (char)byteBuffer.get(); // 하나씩 받는다.
if(byteRead == 0x00){ // 종료 문자라면, while을 탈출한다.
break;
}
message += byteRead; // 종료 문자가 아니면, message 에 추가한다.
}
if(byteRead == 0x00){ // 종료 문자라면 while을 탈출한다.
break;
}
byteBuffer.clear(); // 버퍼 clear.
}
return message; // 하나하나씩 모아진 message를 return 한다.
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
'기타 > JAVA' 카테고리의 다른 글
[JAVA] 객체와 클래스 (0) | 2018.07.09 |
---|---|
[JAVA] 추상클래스 (abstract) / 인터페이스 (interface) (0) | 2018.07.08 |
[JAVA] Calendar 클래스 (0) | 2018.07.08 |
[JAVA] Map-SortedMap / TreeMap 사용하기 (0) | 2018.07.08 |
[JAVA] Map / HashMap 사용하기 (0) | 2018.07.08 |