소켓이란 ? 네트워크로 연결되어 있는 컴퓨터의 통신의 접점에 위치한 통신 객체다. 네트워크 통신을 위한 프로그램들은 소켓을 생성하고, 이 소켓을 통해서 서로 데이터를 교환한다.
- 사전적인 의미로는 연결, 구멍, 콘센트 등을 의미한다.
- 네트워크 환경에 연결할 수 있게 만들어진 연결부이다.
서버(Server)
1. 수신 소캣을 생성한다. (socket)
2. ip주소와 포트번호를 결정하여 소켓에 적용시킨다. (bind)
3. 클라이언트 요청을 대기하는 상태(listen 상태)로 변경한다. (listen)
4. 서버에 접속한 클라이언트와 통신할 수 있는 새로운 소켓을 생성한다. (accept)
5. 데이터 송수신을 한다. (recv, send)
6. 끝 (close)
클라이언트(Client)
1. 송신 소켓을 생성한다. (socket)
2. 서버에 접속한다. (connect)
3. 데이터를 송수신한다. (recv, send)
4. 끝 (close)
ServerSocket
: 클라이언트와 통신할 때 사용하는 클래스
InetSocketAddress
: 소켓 사용시 호스트이름(메인주소)과 포트번호를 관리하는 클래스
Socket
: 클라이언트가 서버와 통신할 때 사용하는 클래스
ServerSocket serverSocket = null;
try {
// ServerSocket 생성
serverSocket = new ServerSocket();
// InetSocketAddress 생성
InetSocketAddress address = new InetSocketAddress("localhost", 9090);
// ServerSocket에 InetSocketAddress 연결
serverSocket.bind(address);
// serverSocket는 무한루프로 구현
while(true) {
System.out.println("[서버] 클라이언트 접속을 기다리는 중");
Socket client = serverSocket.accept();
InetSocketAddress clientAddress = (InetSocketAddress)client.getRemoteSocketAddress();
System.out.println("접속이 허용된 클라이언트 : " + clientAddress.getHostName());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(serverSocket.isClosed() == false) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
ServerSocket()
으로 서버를 생성하고, InetSocketAddress()
로 주소를 부여한다.
그리고 서버는 클라이언트가 접속된 동안 계속 문제없이 구동되어야 하기때문에 무한루프로 구현을 해보았다.
Socket clientSocket = null;
try {
// Socket 생성
clientSocket = new Socket();
// 접속할 Server의 InetSocketAddress 생성
InetSocketAddress address = new InetSocketAddress("localhost", 9090);
// 서버에 접속
clientSocket.connect(address);
System.out.println("[클라이언트] 접속 성공");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(clientSocket.isClosed() == false) {
clientSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Socket()
으로 클라이언트 Socket을 생성하고, InetSocketAddress()
를 이용하여 서버와 같은 주소를 부여한다.
그리고 connect()
메소드를 활용하여 서버와 연결하면 [클라이언트] 접속 성공
메세지를 띄운다.
ServerSocket serverSocket = null;
try {
// serverSocket 생성
serverSocket = new ServerSocket();
// serverSocket의 호스트/포트번호 설정
serverSocket.bind(new InetSocketAddress("localhost", 9099));
// 접속한 클라이언트 개수
int clientCnt = 0;
// 서버는 종료 없이 무한루프
while(true) {
System.out.println("[서버] 클라이언트 접속 기다리는 중");
// 클라이언트 접속 및 카운팅
Socket clientSocket = serverSocket.accept();
clientCnt++;
// 클라이언트에게 "Welcome" 메시지 전송 (목적지를 명시해야함)
// 바이트 출력 스트림 중에서 DataOutputStream은 writeUTF() 메소드를 이용해서
// 한글을 깨짐 없이 보낼 수 있다.
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
out.writeUTF("[서버] 게스트 " + clientCnt + "님 환영합니다!");
// 클라이언트가 보낸 메세지 확인
// 클라이언트가 OutputStream의 write()로 보냈으므로
// InputStreamReader의 read()로 확인
InputStreamReader in = new InputStreamReader(clientSocket.getInputStream());
char[] cbuf = new char[5];
int readCnt = 0; // 실제로 읽은 바이트 수
StringBuilder sb = new StringBuilder();
while((readCnt = in.read(cbuf)) != -1) {
sb.append(cbuf, 0, readCnt); // byte는 offset지정불가라서 String으로함
}
System.out.println("[서버] 클라이언트가 보낸 메세지 : " + sb.toString());
// 입출력 스트림 종료
in.close();
out.close();
// 클라이언트 접속 종료
clientSocket.close();
// 접속한 클라이언트가 3명이면 무한루프 종료
if(clientCnt == 3) {
System.out.println("[서버] 서버가 종료되었습니다.");
serverSocket.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
이번엔 클라이언트가 입력한 메세지를 Scanner로 인식하여 서버가 인식하는 프로그램이다.
InputStreamReader
를 활용하여 메세지를 읽어오도록 했다.
여기서 중요한 점은 입출력 스트림을 닫아줄 때 가장 나중에 닫아주어야 한다.