- Published on
[ Socket ] 소켓 프로그래밍 개요
- Authors
- Name
- 유사공대생
소켓 프로그래밍
소켓 프로그래밍은 소켓을 이용한 통신 프로그래밍이다. 소켓(Socket)이란 프로세스간의 통신에 사용되는 양쪽 끝단(endpoint)를 의미한다. 서로 멀리 떨어진 두 사람이 통신하기 위해서 전화기가 필요한 것 처럼, 프로세스간의 통신을 위해서는 그 무언가가 필요하고, 그것이 바로 소켓이다.
자바에서는 java.net
패키지를 통해 소켓 프로그래밍을 지원하는데, 소켓 통신에 사용되는 프로토콜에 따라 다른 종류의 소켓을 구현하여 제공한다.
TCP와 UDP
TCP/IP 프로토콜은 이기종 시스템간의 통신을 위한 표준 프로토콜로 프로토콜의 집합이다. TCP와 UDP 모두 TCP/IP 프로토콜(TCP/IP protocol suites)에 포함되어 있으며, OSI 7계층의 전송계층(transport layer)에 해당하는 프로토콜이다.
TCP와 UDP는 전송 방식이 다르며, 각 방식에 장단점이 있다. 어플리케이션의 특징에 따라 적절한 프로토콜을 선택하여 사용하도록 하자.
항목 | TCP | UDP |
---|---|---|
연결 방식 | 연결방식(connection-oriented) - 연결 후 통신(전화기) - 1:1 통신방식 | 비연결기반(connectionless-oriented) - 연결없이 통신(소포) - 1:1, n:n 통신 방식 |
특징 | 데이터의 경계를 구분안함(byte-stream) 신뢰성 있는 데이터 전송 - 데이터 전송순서가 보장됨 - 데이터 수신여부를 확인함(데이터가 손실되면 재전송됨) - 패킷을 관리할 필요가 없음 UDP보다 전송속도가 느림 | 데이터의 경계를 구분함.(datagram) 신뢰성 없는 데이터 전송 - 데이터의 전송순서가 바뀔 수 있음 - 데이터의 수신여부를 확인 안함(데이터가 손실되어도 알 수 없음) - 패킷을 관리해주어야 함 TCP보다 전송속도가 빠름 |
관련 클래스 | Socket ServerSocket | DatagramSocket DatagramPacket MulticastSocket |
TCP 소켓 프로그래밍
TCP 소켓 프로그래밍은 클라이언트와 서버간의 일대일 통신이다. 먼저 서버 프로그램 실행되어 클라이언트 프로그램의 연결요청을 기다리고 있어야 한다. 서버 프로그램과 클라이언트 프로그램간의 통신과정을 단계별로 보면 다음과 같다.
- 서버 프로그램에서는 서버소켓을 이용해서 서버 컴퓨터의 특정 포트에서 클라이언트의 연결요청을 처리할 준비를 한다.
- 클라이언트 프로그램은 접속할 서버의 IP주소와 포트 정보를 가지고 소켓을 생성해서 서버에 연결을 요청히다.
- 서버소켓은 클라이언트의 연결요청을 받으면 서버에 새로운 소켓을 생성해서 클라이언트의 소켓과 연결되도록 한다.
- 이제 클라이언트의 소켓과 새로 생성된 서버의 소켓은 서버소켓과 관계없이 일대일 통신을 한다.
서버소켓(ServerSocket)은 포트와 결합(bind)되어 포트를 통해 원격 사용자의 연결요청을 기다리다가 연결요청이 올 때마다 새로운 소켓을 생성하여 상대편 소켓과 통신할 수 있도록 연결한다. 여기까지가 서버소켓의 역할이고, 실제적인 데이터 통신은 서버소켓과 관계없이 소켓과 소켓 간에 이루어진다.
여러 개의 소켓이 하나의 포트를 공유해서 사용할 수 있지만, 서버소켓은 다르다. 서버소켓은 포트를 독점한다. 만일 한 포트를 둘 이상의 서버소켓과 연결하는 것이 가능하다면 클라이언트 프로그램이 어떤 서버소켓과 연결되어야하는지 알 수 없을 것이다.
포트(port)는 호스트(컴퓨터)가 외부와 통신을 하기 위한 통로로 하나의 호스트가 65536개의 포트를 가지고 있으며 포트는 번호로 구별된다. 포트의 번호는 0~65535의 범위에 속하는 값인데 보통 1023번 이하의 포트는 FTP나 Telnet과 같은 기존의 다른 통신 프로그램들에 의해서 사용되는 경우가 많기 때문에 1023번 이상의 번호 중에서 사용하지 않는 포트를 골라서 사용해야 한다.
두 서버소켓이 서로 다른 프로토콜을 사용하는 경우에는 같은 포트를 사용할 수 있다. 포트는 같아도 클라이언 트 프로그램이 사용하는 프로토콜로 어떤 서버소켓과 연결되어야 하는지 구별할 수 있기 때문이다. 그래도 가능하면 하나의 포트는 하나의 서버소켓만 사용하도록 하는 것이 바람직하다.
정리하면, **서버소켓은 소켓간의 연결만 처리하고 실제 데이터는 소켓들끼리 서로 주고받는다. **소켓들이 데이터를 주고받는 연결통로는 바로 입출력스트림이다.
입출력스트림
소켓은 입력스트림, 출력스트림 두개를 가지고 있다. 이 스트림들은 연결된 상대편 소켓의 스트림들과 교차연결된다.
한 소켓의 입력스트림은 상대편 소켓의 출력스트림과 연결되고, 출력스트림은 입력스트림으로 연결된다. 그래서 한 소켓에서 출력스트림으로 데이터를 보내면 상대편 소켓에서는 입력스트림으로 받게 된다.
자바에서 TCP 소켓프로그래밍에서는 Socket
, ServerSocket
클래스를 제공한다.
Socket
: 프로세스간의 통신을 담당하며, InputSteam과 OutputStream을 가지고 있다. 이 두 스트림을 통해 프로세스간의 통신(입출력)이 이루어진다.ServerSocket
: 포트와 연결(bind)되어 외부의 연결요청을 기다리다 연결 요청이 들어오면,Socket
을 생성해서 소켓과 소켓간의 통신이 이루어지도록 한다. 한 포트에 하나의ServerSocket
만 연결할 수 있다.(프로토콜이 다르면 같은 포트를 공유할 수 있다.)
서버 예시 코드
import java.net.ServerSocket;
import java.io.*;
import java.net.Socket;
import java.util.Date;
import java.text.SimpleDateFormat;
public class TcpIpServer {
public static void main(String args[]) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(7777); // 서버소켓을 생성, 7777 포트와 바인드(bind)
System.out.println(getTime() + "서버가 준비되었습니다.");
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
System.out.println(getTime() + "연결요청을 기다립니다.");
// 서버소켓은 클라이언트의 연결요청이 올 때까지 실행을 멈추고 계속 기다림
// 클라이언트의 연결요청이 오면 클라이언트 소켓과 통신할 새로운 소켓을 생성
Socket socket = serverSocket.accept();
System.out.println(getTime() + socket.getInetAddress() +
"로부터 연결 요청이 들어왔습니다.");
// 소켓의 출력스트림 얻기
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
// 원격 소켓(remote socket)에 데이터를 보냄
dos.writeUTF("[Notice] Test Message1 from Server.");
System.out.println(getTime() + "데이터를 전송했습니다.");
// 스트림과 소켓을 닫음
dos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
static String getTime() {
SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
return f.format(new Date());
}
}