Socket
TCP/IP 기반 네트워크 통신에서 데이터 송수신의 마지막 접점을 의미합니다.
프로토콜과 IP주소, 포트 넘버로 구성되며 클라이언트/서버 구조로 동작합니다.
Socket 통신의 흐름
서버 흐름
- 소켓 생성
IP
와Port
번호를 설정하는 바인딩 작업 수행listen
으로 클라이언트 요청 대기accept
로 클라이언트와 연결- 데이터 송수신
- 소켓 닫기
클라이언트 흐름
- 소켓 생성
- 서버에 설정된
ip
와port
로 연결 - 데이터 송수신
- 소켓 닫기
ServerSocket
서버측에서 클라이언트의 접속을 대기하며 클라이언트 접속 시 접속을 허용하고 통신하기 위한 클래스입니다.
실제 모든 작업은 SocketImpl
인스턴스가 수행하게 되며 생성자 호출 시 인스턴스를 생성합니다.
내부 bind와 accept함수를 보면 모든 작업 수행 시 socketImpl을 호출하는 것을 확인할 수 있습니다.
ServerSocket 생성자
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException("Port value out of range: " + port);
if (backlog < 1)
backlog = 50;
this.impl = createImpl();
try {
bind(new InetSocketAddress(bindAddr, port), backlog); // bind 함수
} catch (IOException | SecurityException e) {
close();
throw e;
}
}
ServerSocket bind함수
public void bind(SocketAddress endpoint, int backlog) throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (isBound())
throw new SocketException("Already bound");
if (endpoint == null)
endpoint = new InetSocketAddress(0);
if (!(endpoint instanceof InetSocketAddress epoint))
throw new IllegalArgumentException("Unsupported address type");
if (epoint.isUnresolved())
throw new SocketException("Unresolved address");
if (backlog < 1)
backlog = 50;
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkListen(epoint.getPort());
// SocketImpl bind+listen throw if already bound or closed
SocketImpl impl = getImpl();
impl.bind(epoint.getAddress(), epoint.getPort());
impl.listen(backlog); //listen
bound = true;
}
ServerSocket accept 함수
public Socket accept() throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!isBound())
throw new SocketException("Socket is not bound yet");
Socket s = new Socket((SocketImpl) null);
implAccept(s);
return s;
}
Socket
클라이언트 사이드에서 서버와 통신하기 위한 클래스입니다.
서버 소켓과 마찬가지로 모든 작업은 SocketImpl
인스턴스가 수행하게 됩니다.
Socket 생성자
생성자 요청 시 내부에서 SocketImpl을 생성하는 것을 확인 할 수 있습니다.
public Socket(String host, int port)
throws UnknownHostException, IOException
{
this(host != null ? new InetSocketAddress(host, port) :
new InetSocketAddress(InetAddress.getByName(null), port),
(SocketAddress) null, true);
}
private Socket(SocketAddress address, SocketAddress localAddr, boolean stream)
throws IOException
{
Objects.requireNonNull(address);
// create the SocketImpl and the underlying socket
SocketImpl impl = createImpl();
impl.create(stream);
this.impl = impl;
this.state = SOCKET_CREATED;
try {
if (localAddr != null)
bind(localAddr);
connect(address);
} catch (IOException | IllegalArgumentException | SecurityException e) {
try {
close();
} catch (IOException ce) {
e.addSuppressed(ce);
}
throw e;
}
}
서버-클라이언트 구조 구현해보기
간단히 하나의 클라이언트가 접속해보는 구조를 구현해서 확인해보겠습니다.
서버 구현
public class MyServer {
public static void main(String[] args) {
System.out.println("서버 소켓 시작하기-!");
// 1. 포트번호를 매개변수로 지정하여 서버 소캣을 생성한 후 클라이언트의 접속을 기다린다.
try (ServerSocket serverSocket= new ServerSocket(9999);
// 2. 클라이언트의 접속 요청이 들어오면 accept() 메서드가 실행되어 클라이언트와의 통신을 위한 Socket 객체를 생성한다.
Socket socket = serverSocket.accept();
// 3.생성된 Socket 객체로부터 통신을 위한 InputStream, OutputStream을 얻는다.
OutputStream os = socket.getOutputStream()){
System.out.println("클라이언트가 접속했어-!");
// 5.InputStream, OutputStream을 이용하여 클라이언트와 통신한다.
os.write("안녕 넌 서버에 접속을 성공했단다~".getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
클라이언트 구현
public class MyClient {
public static void main(String[] args) {
// 1 .서버의 IP주소와 Port번호를 매개변수로 지정하여 서버와 통신을 위한 Socket 객체를 생성한다.
try (Socket socket = new Socket("localhost", 9999);
// 2. Socket 객체로부터 서버와의 통신을 위한 InputStream, OutputStream을 얻는다.
BufferedReader br= new BufferedReader (new InputStreamReader(socket.getInputStream(),"UTF-8"))){
System.out.println("서버에 접속 완료-!");
// 3.생성된 InputStream, OutputStream을 이용하여 서버와 통신한다.
System.out.println("서버가 준 메시지 :" + br.readLine());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
오늘은 간단히 소켓에 대해 공부하고 소켓 통신을 구현해봤습니다.
서버측에서 클라이언트를 관리하고 스레드를 활용한다면 채팅 구조도 만들어 볼 수 있을 것 같습니다.
다음에는 채팅구조를 만들어 한번 작성해보겠습니다.
'BackEnd > JAVA' 카테고리의 다른 글
[Java] Thread 동기화가 필요해. (0) | 2025.04.18 |
---|---|
[JAVA] 함수형 인터페이스라는게 있더라구요..(feat.Lambda) (0) | 2025.03.14 |
[JAVA] 빈 생명주기 콜백 (0) | 2024.06.14 |
[JAVA] ThreadLocal에 대해 알아보자 (0) | 2022.09.06 |
[JAVA] Char type to Integer type 주의할 점! (0) | 2022.07.05 |