TCP 네트워킹
- TCP 특징
- transmission control protocol → 전송 제어 방식
- 클라이언트와 서버가 연결을 확인한 상태에서 데이터를 전송함
- 고정된 통신선로(일종의 전용도로)를 확보해둠
- 데이터를 순차적으로 보냄
- 정확하고 안정적인 방식
- 시간이 오래걸림. 특히 연결하는 단계에서 시간이 가장 많이 소요됨
- ex) 공 던질거야, 들었지? (응답확인) 이거 몇번째 공니까 잘 받아라!! 잘 받았지? (응답확인)
- Java TCP 네트워킹
- 서버와 클라이언트의 데이터 통신은 ServerSocket 과 Socket 객체를 사용한다.
클래스 | 역할 |
java.net.ServerSocket | -통신연결 요청을 대기하다가 연결요청이 들어오면 연결을 수락 -데이터 수신(받기) -보통 서버에서 사용하는 클래스 |
java.net.Socket | -상대방의 통신장비와의 연결상태를 보관하는 역할 -데이터 전송(보내기) -보통 클라이언트에서 사용하는 클래스 |
서버에서는 ServerSocket, Socket 클래스 둘다 필요하고 , 클라이언트는 Socket 클래스만 있으면 된다
다만, 서버에서는 ServerSocket 클래스의 메서드를 사용해 Socket 객체를 받을 수 있다. 때문에 new 연산자로 반드시 객체를 선언할 필요는 없다.
정리하자면 (데이터를 수신하는) 서버는 ServerSocket 객체, (데이터를 보내는) 클라이언트는 Socket 객체를 선언해 사용하면 된다.
아래에서 통신을 위한 클래스, 메서드에 대해 알아본다.
ServerSocket
-서버에서 사용하는 클래스
-클라이언트로부터 연결요청 받으면 연결을 수락한다
- ServerSocket 주요 생성자
- ServerSocket() 생성자로 생성시-> 객체만 생성한다
- ServerSocket(인자값) 생성자로 생성시 -> 바로 연결대기(listening) 상태가 된다.
ip가 원격지 주소라면, port 는 일종의 전용통로다. 포트번호는 원하는 숫자로 지정할 수 있다. 참고로 0 ~ 1023 포트는 다른 프로그램에서 사용하기 때문에 다른 포트를 사용한다. 코드 실행시 해당 포트가 사용중이라면 BindException이 발생한다.
생성자 | 내용 |
ServerSocket() | -포트 지정하지 않고 생성하기 -객체만 생성한다 |
ServerSocket(int port) | -포트 지정해 생성하기 -객체 생성 뒤 바로 연결대기 상태가 됨 |
ServerSocket(int port, int backlog) | -backlog : 연결할 큐 개수(기본값은 50) -객체 생성 뒤 바로 연결대기 상태가 됨 |
ServerSocket(int port, int backlog, InetAddress bindAddr) | -bindAddr : 특정 주소에서만 접근가능하도록 제한 -객체 생성 뒤 바로 연결대기 상태가 됨 |
- ServerSocket 주요 메서드
수신에 사용되는 메서드는 accept() 이다
메서드 | 내용 |
Socket accept() | 연결 요청 수락하기 |
void bind(SocketAddress endpoint) | 서버소켓을 특정 주소로 연결하기 |
void close() | 소켓 닫기 |
ServerSocketChannel getChannel() | ServerSocketChannel object 리턴 |
InetAddress getInetAddress() | 서버소켓의 local address 리턴 |
int getLocalPort() | 요청대기 중인 포트번호 리턴 |
SocketAddress getLocalSocketAddress() | 해당 소켓이 바인딩된 종점의 주소값 리턴 |
boolean isBound() | 서버소켓의 바인딩 상태를 리턴 |
boolean isClosed() | 서버소컷이 닫혔는지 여부 리턴 |
void setPerformancePreferences( int connectionTime, int latency, int bandwidth) |
서버소켓의 퍼포먼스 설정 |
String toString() | 주소(ip+port)를 String값으로 리턴 |
Socket
-원격지와의 연결상태를 보관하고, 원격지에 데이터를 전송한다
-클라이언트에서는 직접 Socket 객체를 생성한다. 서버는 클라이언트에서 접속(연결요청)을 하면 Socket 객체를 생성할 수 있다
- Socket 주요 생성자
-ServerSocket 클래스 처럼 Socket 클래스도 객체만 생성하는 방식과 객체 생성과 동시에 서버연결되는 생성자로 나뉜다.
-연결할 수 있는 address, port 를 제공하면 자동으로 연결된다
생성자 | 내용 |
Socket() | -소켓 기본생성자 -객체만 생성 |
Socket(InetAddress address, int port) | -InetAddress, port 인자값으로 주기 -객체생성 후 해당 서버에 연결 |
Socket(Proxy proxy) | -Proxy 인자값으로 주기 -객체만 생성 |
Socket(String host, int port) | -host, port 인자값으로 주기 -객체생성 후 해당 서버에 연결 |
Socket( String host, int port, InetAddress localAddr, int localPort ) |
-host, port 인자값으로 주기 -객체생성 후 해당 서버에 연결 -지정된 local 주소에 접속하기 |
- Socket 주요 메서드
메서드 | 내용 |
void close() | 소켓 닫기 |
void connect(SocketAddress endpoint) | 소켓과 서버 연결 |
InetAddress getInetAddress() | 소켓이 연결된 주소 리턴 |
InputStream getInputStream() | InputStream 리턴 |
InetAddress getLocalAddress() | 소켓이 바인딩된 주소 리턴 |
int getLocalPort() | 소켓이 바인딩된 포트 리턴 |
SocketAddress getLocalSocketAddress() | 소켓이 바인딩된 종점의 주소 리턴 |
OutputStream getOutputStream() | OutputStream 리턴 |
int getPort() | 소켓이 연결된 포트 리턴 |
SocketAddress getRemoteSocketAddress() | 소켓이 연결된 주소 리턴 연결되지 않았다면 null 리턴 |
boolean isBound() | 소켓의 바인딩 상태 리턴 |
boolean isClosed() | 소켓이 닫혔는지 여부 |
boolean isConnected() | 소켓이 연결되었는지 여부 |
객체를 생성하고 연결대기 혹은 연결요청하는 코드를 짜본다
1. 서버(server)
- 단일 클라이언트 연결
서버는 다수의 클라이언트와 통신하는 경우가 많다. 먼저 클라이언트 1개와 통신할 수 있는 코드이다. 연결 전까지 코드실행은 block 된다.
public class Test01 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
//ServerSocket 객체 생성
serverSocket = new ServerSocket();
//ServerSocket 객체에 특정주소 바인딩
serverSocket.bind(new InetSocketAddress("localhost", 7000));
//클라이언트 요청 수락. Socket 생성
serverSocket.accept();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try{
if(!serverSocket.isClosed()){ serverSocket.close(); }
} catch (IOException e){
e.printStackTrace();
}
}
}
}
- 다중 클라이언트 연결
클라이언트 여러개와 통신할 수 있는 코드이다. while 문을 도입하여 accept()를 반복호출해 Socket 객체를 생성한다. 연결 전까지 코드실행은 block 된다.
public class Test02 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
//ServerSocket 객체 생성
serverSocket = new ServerSocket();
//ServerSocket 객체에 특정주소 바인딩
serverSocket.bind(new InetSocketAddress("localhost", 7000));
while(true){
//클라이언트 요청 수락. Socket 생성
serverSocket.accept();
}
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try{
if(!serverSocket.isClosed()){ serverSocket.close(); }
} catch (IOException e){
e.printStackTrace();
}
}
}
}
2. 클라이언트(client)
클라이언트에서는 연결할 소켓을 생성하여 서버와 통신할 수 있다. ip, port가 일치해야 통신할 수 있다
public class Test01 {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress("localhost", 7000));
} catch (IOException ioe){
ioe.printStackTrace();
} finally {
try {
if(!socket.isClosed()){
socket.close();
}
} catch (IOException ioe){
ioe.printStackTrace();
}
}
}
}
- 클라이언트에서 연결 실패한 경우
- ip 혹은 port가 일치하지 않아서
- 서버 보다 클라이언트를 먼저 실행한 경우
실행 결과
java.net.ConnectException: Connection refused: connect ... (이하 생략) |
이제 ServerSocket, Socket 클래스를 사용해 간단한 통신 테스트를 해보자
- 서버 단
public class Test_server {
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
//ServerSocket 객체 생성
serverSocket = new ServerSocket();
//ServerSocket 객체에 특정주소 바인딩
serverSocket.bind(new InetSocketAddress("localhost", 7000));
while(true){
System.out.println("server - 연결 대기");
//클라이언트 요청 수락. Socket 생성
Socket socket = serverSocket.accept();
SocketAddress addr = socket.getRemoteSocketAddress();
System.out.println(addr.toString());
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (Exception e){
e.printStackTrace();
} finally {
try{
System.out.println("server - close");
if(!serverSocket.isClosed()){
serverSocket.close();
}
} catch (IOException ioe){
ioe.printStackTrace();
}
}
}
}
- 클라이언트 단
연결되고 1초후에 자동으로 연결을 종료한다.
public class Test_client {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress("localhost", 7000));
System.out.println("client 연결 성공");
SocketAddress addr = socket.getRemoteSocketAddress();
System.out.println("연결정보 : "+ addr.toString());
} catch (ConnectException ce){
ce.printStackTrace();
} catch (IOException ioe){
ioe.printStackTrace();
} finally {
try {
Thread.sleep(1000);
System.out.println("client - close");
if(!socket.isClosed()){
socket.close();
}
} catch (InterruptedException ie){
ie.printStackTrace();
} catch (IOException ioe){
ioe.printStackTrace();
}
}
}
}
실행 결과 - 클라이언트
client 연결 성공 연결정보 : localhost/127.0.0.1:7000 client - close |
실행 결과 - 서버
server - 연결 대기 /127.0.0.1:58775 server - 연결 대기 /127.0.0.1:62118 server - 연결 대기 /127.0.0.1:62124 server - 연결 대기 |
TCP를 이용한 데이터는 스트림을 사용한다.
다음 포스트에서 이에 대해 알아보자
'Java > 기본' 카테고리의 다른 글
[Java] 인터페이스 안에 필드, 메서드, 클래스 선언하기 (0) | 2021.09.08 |
---|---|
[Java] 네트워킹 - UDP (0) | 2021.07.31 |
[Java] 네트워킹 - InetAddress (update.2021-11-11) (0) | 2021.07.30 |
[Java] IO스트림 사용하기 - 객체 직렬화(Serialize) (0) | 2021.07.25 |
[Java] IO스트림 사용하기 - 스트림 연결하기(Stream chaining) (0) | 2021.07.25 |