프로세스 간의 통신에 사용되는 양쪽 끝단을 의미한다.
- 패키지 :
java.net
- 소켓 프로그래밍은 클라이언트(Client)와 서버(Server)가 통신할 수 있는 환경을 설계하는 것이다.
- 데이터를 주고 받을 수 있는 구조체로 소켓을 통해 데이터 통로가 만들어 진다.
소켓은 응용프로그램에서 TCP/IP를 이용하는 창구 역할을 하며, 두 프로그램이 네트워크를 통해 서로 통신을 수행할 수 있도록 양쪽에서 생성되는 링크의 단자이다.
두 소켓이 연결되면 서로 다른 프로그램이 서로 데이터를 전달할 수 있다.
- 먼저 기다리는 측을
Server
라고 하며,Server
에서는 Port를 열고Client
의 접속을 기다린다.- 접속하는 측을
Client
라고 하며,Server
의 IP와 Port에 접속하여 통신 연결한다.Server
와Client
간의 통신은 Send, Receive의 형태로 주고 받는다.- 통신이 끝나면
close()
로 접속을 끊는다.
TCP
UDP
HTTP 통신
Client의 요청(Request)가 있을 때 서버가 응답(Response)하여 해당 정보를 전송하고 바로 연결 종료한다.
Socket 통신
Server와 Client가 특정 Port를 통해 실시간으로 양방향 통신
ServerSocket
클라이언트와 통신할 때 사용하는 클래스
InetSocketAddress
Socket 사용 시 호스트이름(메인주소)과 포트번호를 관리하는 클래스
Socket
클라이언트가 서버와 통신할 때 사용하는 클래스
예제 1
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerMain {
public static void main(String[] args) {
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 clientaddAddress = (InetSocketAddress)client.getRemoteSocketAddress();
System.out.println("접속이 허용된 클라이언트 : " + clientaddAddress.getHostName());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(serverSocket.isClosed() == false) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
serverSocket()
으로 서버를 생성하고, InetSocketAddress()
로 주소를 부여한다.
그리고 서버는 클라이언트가 접속된 동안 계속 문제 없이 구동되어야 하기 때문에 무한루프로 구현했다.
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
public class ClientMain {
public static void main(String[] args) {
Socket clientSocket = null;
try {
// Socket 생성
clientSocket = new Socket();
// 접속할 Server의 InetSocketAddress 연결
InetSocketAddress address = new InetSocketAddress("localhost", 9090);
// http://localhost:9090
// 서버 접속
clientSocket.connect(address);
System.out.println("[클라이언트] 접속 성공");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(clientSocket.isClosed() == false) {
clientSocket.close();
System.out.println("서버 중지");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Socket()
으로 클라이언트 Socket을 생성하고, InetSocketAddress()
를 이용해서 서버와 같은 주소를 부여한다.
connect()
메소드를 활용하여 서버와 연결하면 "[클라이언트] 접속 성공" 메시지를 띄운다.
예제 2
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Scanner;
public class ClientMain {
public static void main(String[] args) {
Socket clientSocket = null;
try {
// Socket 생성
clientSocket = new Socket();
// 서버 접속
clientSocket.connect(new InetSocketAddress("localhost", 9099));
// 서버에 접속되면 Welcome 메시지가 넘어옴
// 서버가 DataOutputStream의 writeUTF()로 메시지를 전송하므로
// 클라이언트는 DataInputStream의 readUTF()로 메시지를 받음
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
String message = in.readUTF();
System.out.println("[클라이언트] " + message);
// Scanner 클래스를 이용해 입력 받은 데이터를 서버로 전송
Scanner sc = new Scanner(System.in);
System.out.println("서버로 전송할 메시지 >>> ");
String send = sc.nextLine();
OutputStreamWriter out = new OutputStreamWriter(clientSocket.getOutputStream());
out.write(send);
// 입출력 스트림 종료
out.close();
in.close();
sc.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(clientSocket.isClosed() == false) {
System.out.println("[클라이언트] 클라이언트 종료");
clientSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerMain {
public static void main(String[] args) {
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 + "님 환영합니다!");
out.close();
// 클라이언트가 보낸 메시지 확인
// 클라이언트가 OutputStreamWriter의 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());
// 입출력 스트림 종료
out.close();
in.close();
// 클라이언트 접속 종료
clientSocket.close();
// 접속한 클라이언트가 3명이면 무한루프 종료
if(clientCnt == 3) {
System.out.println("[서버] 서버가 종료되었습니다.");
serverSocket.close();
break;
}
} // while(true)
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(serverSocket.isClosed() == false) {
System.out.println("[서버] 서버가 종료되었습니다.");
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
클라이언트가 입력한 메시지를 Scanner로 인식하여 서버가 인식하는 프로그램이다.
InputStreamReader
를 사용해 메시지를 읽었다.