Skip to content
SeoSiun edited this page Jul 17, 2023 · 2 revisions

Socket?

  • TCP/IP 기반 네트워크 통신에서 데이터 송수신

  • 양방향 연결 지향성 통신

    • 지속적으로 연결을 유지하면서 실시간으로 데이터를 주고받아야 하는 경우 사용.
  • Process to Process 통신

  • IP와 Port number를 통해 연결

    • IP: 통신을 할 컴퓨터(device)를 식별
    • Port number: 해당 컴퓨터 내에서 현재 통신에 사용될 응용프로그램(프로세스) 식별
  • 소켓의 역할에 따라 클라이언트 소켓과 서버 소켓으로 구분

    • 서버: 데이터를 제공하는 쪽
    • 클라이언트: 데이터를 요청하여 제공받는 쪽

통신 흐름

  • 서버

    • 서버소켓 생성
    • IP, port 바인딩
    • 클라이언트 접속 대기
  • 클라이언트

    • 클라이언트 소켓 생성
    • 서버의 IP, port로 통신 시도
    • 연결 후 read(), write()로 통신
  • cf) 하나의 서버에 여러 클라이언트가 접속한다면?

    • 클라이언트 하나 당 한 개의 Socket(하나의 커넥션)이 생성됨

      ⇒ Thread를 사용하자!

Socket vs. HTTP

  • HTTP
    • 클라이언트의 요청이 있을 때 서버가 요청 수행 및 응답을 보내고, 바로 연결 종료
    • 클라이언트가 요청을 보낼 때만 서버가 응답하는 단방향 통신 (서버가 클라이언트에 요청을 보낼 수는 없음)
  • Socket
    • 서버와 클라이언트가 특정 포트를 통해 실시간으로 양방향 통신
    • 서버와 클라이언트의 연결이 계속 유지되는 양방향 통신

ServerSocket

  • 클라이언트 소켓의 연결 요청을 기다리다가(block), 요청이 오면 클라이언트와 통신하기 위한 소켓(Socket 객체)를 생성하여 리턴

    • 이때 새로 생성된 소켓은 ServerSocket과 다른 포트를 사용 (랜덤한 포트가 할당됨)
    • ServerSocket이 쓰는 포트는 클라이언트 요청 listen을 위한 포트이므로
    package java.net;
    
    class ServerSocket implements java.io.Closeable {
    	
    	...
    
    	/**
    	/* 넘겨받은 포트에 바인딩된 server socket 생성
    	/* port에 0을 넘기면 포트를 자동으로 할당해줌.
    	/*  (getLocalPort()를 통해 할당받은 포트 번호 확인 가능)
    	**/
    	public ServerSocket(int port) throws IOException {
        this(port, 50, null);
      }
    
    	...
    
    	/**
    	/* 소켓에 대한 connection을 listen하고 accept함.
    	/* connection이 생성될 때까지 block됨
    	/* 실제 통신을 담당할 Socket 인스턴스를 생성해서 리턴
    	**/
    	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;
      }
    	
    	/**
    	/* (보통 빈) 소켓을 넘겨받아 client에 연결해줌
    	**/
    	protected final void implAccept(Socket s) throws IOException {
        SocketImpl si = null;
        try {
            if (s.impl == null)
              s.setImpl();
            else {
                s.impl.reset();
            }
            si = s.impl;
            s.impl = null;
            si.address = new InetAddress();
            si.fd = new FileDescriptor();
            getImpl().accept(si);
            SocketCleanable.register(si.fd);   // raw fd has been set
    
            SecurityManager security = System.getSecurityManager();
            if (security != null) {
                security.checkAccept(si.getInetAddress().getHostAddress(),
                                     si.getPort());
            }
        } catch (IOException e) {
            if (si != null)
                si.reset();
            s.impl = si;
            throw e;
        } catch (SecurityException e) {
            if (si != null)
                si.reset();
            s.impl = si;
            throw e;
        }
        s.impl = si;
        s.postAccept();
    	}
    
    	...
    
    }

Socket (client socket)

  • 실제 데이터 송수신 담당
  • 두 machine 사이 통신의 endpoint
package java.net;

class Socket implements java.io.Closeable {

	...

	/**
	/* 사용자 정의 SocketImpl으로 unconnected Socket을 생성
	**/
	protected Socket(SocketImpl impl) throws SocketException {
    checkPermission(impl);
    this.impl = impl;
    if (impl != null) {
      checkOldImpl();
      this.impl.setSocket(this);
    }
  }

	...

	/**
	/* 해당 Socket에 대한 input stream 반환
	**/
	public InputStream getInputStream() throws IOException {
    if (isClosed())
      throw new SocketException("Socket is closed");
    if (!isConnected())
      throw new SocketException("Socket is not connected");
    if (isInputShutdown())
      throw new SocketException("Socket input is shutdown");
    InputStream is = null;
    try {
	    is = AccessController.doPrivileged(
	      new PrivilegedExceptionAction<>() {
	        public InputStream run() throws IOException {
	          return impl.getInputStream();
	        }
      });
    } catch (java.security.PrivilegedActionException e) {
      throw (IOException) e.getException();
    }
    return is;
  }

	/**
	/* 해당 Socket에 대한 output stream 반환
	**/
	public OutputStream getOutputStream() throws IOException {
    if (isClosed())
      throw new SocketException("Socket is closed");
    if (!isConnected())
      throw new SocketException("Socket is not connected");
    if (isOutputShutdown())
      throw new SocketException("Socket output is shutdown");
    OutputStream os = null;
    try {
        os = AccessController.doPrivileged(
          new PrivilegedExceptionAction<>() {
            public OutputStream run() throws IOException {
              return impl.getOutputStream();
            }
          });
    } catch (java.security.PrivilegedActionException e) {
      throw (IOException) e.getException();
    }
    return os;
  }

	...

}

Clone this wiki locally