여러 대의 컴퓨터를 통신 회선으로 연결한 것(홈 네트워크, 지역 네트워크, 인터넷 등이 해당)
여러 통신기기들을 서로 연결하여 데이터를 손쉽게 주고받거나 자원 등을 공유하기 위해 사용
네트워크로 연결된 컴퓨터간의 관계를 역할(role)로 구분한 개념
서버는 서비스를 제공하는 프로그램으로 클라이언트의 연결을 수락하고
요청 내용을 처리 후 응답을 보내는 역할
클라이언트는 서비스를 받는 프로그램으로 네트워크 데이터를 필요로 하는
모든 어플리케이션이 해당 됨
네트워크 상에서 컴퓨터를 식별하는 번호로 네트워크 어댑터(랜카드)마다 할당 되어 있음
같은 컴퓨터 내에서 프로그램을 식별하는 번호로
클라이언트는 서버 연결 요청 시 IP주소와 포트 번호를 알아야 함
클라이언트와 서버간의 1:1 소켓 통신
서버가 먼저 실행 되어 클라이언트의 요청을 기다려야 하고
서버용 프로그램과 클라이언트용 프로그램을 따로 구현해야 함
자바에서는 TCP 소켓 프로그래밍을 위해 java.net패키지에서 ServerSocket과 Socket클래스 제공
UDP는 연결 지향적이지 않기 때문에 연결 요청을 받아줄 서버 소켓이 필요 없음
java.net패키지에서 제공하는 두 개의 DatagramSocket간에
DatagramPacket으로 변환된 데이터 주고 받음
package edu.kh.network.model.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TCPServer {
// Server : 서비스를 제공하는 프로그램 또는 컴퓨터
// Client : 서버에 서비스를 요청하여 사용하는 프로그램 또는 컴퓨터
// TCP Socket 프로그래밍
// TCP : 데이터 전달의 신뢰성을 최대한 보장하기 위한 방식(연결 지향형 통신)
// 순차적으로 데이터를 전달하고 확인 및 오류 시 재전송
// Socket : 프로세스의 통신에 사용되는 양 끝단.
// 서버와 클라이언트가 통신을 하기 위한 매개체
// ServerSocket : 서버용 소켓
// -Port와 연결되어 외부 요청을 기다리는 역할
// -> 클라이언트 요청이 올 경우 이를 수락하고,
// 클라이언트가 사용할 수 있는 소켓을 생성
// --> 서버 소켓과 클라이언트 소켓이 연결되어 데이터 통신이 가능해짐.
public void serverStart() {
// 1. 서버의 포트번호 정함
int port = 8500; // port 번호는 0 ~ 65535 사이지정 가능
// 단, 1023 번 이하는 이미 사용 중인 경우가 많으니 제외
/* 사용할 변수 미리 선언 */
ServerSocket serverSocket = null; // 서버 소켓 저장 변수
Socket clientSocket = null; // 클라이언트 소켓 저장 변수
InputStream is = null; // 클라이언트 -> 서버 입력용 스트림 변수
BufferedReader br = null; // 입력용 보조 스트림 변수
OutputStream os = null; // 서버 -> 클라이언트 출력용 스트림 변수
PrintWriter pw = null; // 출력용 보조 스트림 변수
try {
// 2. 서버용 소켓 객체 생성
serverSocket = new ServerSocket(port); // 서버용 소켓을 생성하여 포트 결합
// 3. 클라이언트 쪽에서 접속 요청이 오길 기다림
// - 서버용 소켓은 생성되고나면 클라이언트 요청이 오기 전까지
// 다음코드 수행하지 않고 대기하고 있음.
System.out.println("[Server]");
System.out.println("클라이언트 요청을 기다리고 있습니다.");
// 4. 접속 요청이 오면 요청 수락 후 해당 클라이언트에 대한 소켓 객체 생성
// -> 요청을 수락하면 자동으로 Socket 객체가 얻어와짐
clientSocket = serverSocket.accept();
// 접속한 클라이언트의 IP를 얻어와 출력
String clientIP = clientSocket.getInetAddress().getHostAddress();
System.out.println(clientIP + "가 연결을 요청함...");
// 5. 연결된 클라이언트와 입출력 스트림 생성
is = clientSocket.getInputStream();
os = clientSocket.getOutputStream();
// 6. 보조 스트림을 통해 성능 개선
br = new BufferedReader( new InputStreamReader(is) );
// InputStreamReader : 문자 기반 스트림과 바이트 기반 스트림 연결에 사용되는 스트림
pw = new PrintWriter( os );
// 7. 스트림을 통해 읽고 쓰기
// 7-1) 서버 -> 클라이언트에게 출력(메세지 전송)
Date now = new Date(); // 생성된 시간을 기록하고 있는 시간 관련 객체
// -> 날짜 출력 형식 변경이 필요함
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sdf.format(now); // now에 저장된 시간 포맷을 변경
pw.println(time + "[서버 접속 성공]");
pw.flush(); // 스트림에 있는 내용을 모두 밀어냄.
// 7-2) 클라이언트 -> 서버에게 입력 (메세지 전송 받기)
String message = br.readLine(); // 클라이언트 메세지 한줄 읽어옴.
System.out.println(clientIP + "가 보낸 메세지 : " + message);
} catch(IOException e) {
e.printStackTrace();
} finally {
// 8. 통신 종료
// 사용한 스트림, 소켓 자원은 모두 반환( close )
try {
// 보조 스트림 close 시 연결된 기반스트림 (is, os)도 같이 close 됨
if(pw != null) pw.close();
if(br != null) br.close();
if(serverSocket != null) serverSocket.close();
if(clientSocket != null) clientSocket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
package edu.kh.network.model.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TCPClient {
public void clientStart() {
// 1. 서버의 IP주소와 서버가 정한 포트번호를 매개변수로 하여 클라이언트용 소켓 객체 생성
String serverIP = "127.0.0.1"; // loop back ip (내 컴퓨터를 가리키는 ip주소)
int port = 8500; // 서버 소켓이 기다리고 있는 포트 번호
// * 필요한 변수 선언 *
Socket clientSocket = null; // 서버와 연결할 클라이언트용 소켓을 저장할 변수
BufferedReader br = null; // 서버 -> 클라이언트로 읽어오는 보조 스트림
PrintWriter pw = null; // 클라이언트 -> 서버로 출력하는 보조 스트림
try {
// 2. 서버와의 입출력 스트림 오픈 -> 먼저 소켓이 필요함
System.out.println("[Client]");
clientSocket = new Socket(serverIP, port);
// 3. 보조 스트림을 통해 성능 개선
br = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) );
pw = new PrintWriter( clientSocket.getOutputStream() );
// 4. 스트림을 통해 읽고 쓰기
// 4-1 ) 서버 접속 성공 시
// 서버가 출력한 "[서버 접속 성공]" 메세지 읽어오기
String message = br.readLine();
System.out.println("서버로부터 받은 메세지 : " + message);
// 4-2) 클라이언트 -> 서버로 메세지 전송
Scanner sc = new Scanner(System.in);
System.out.println("입력 : ");
String input = sc.nextLine();
pw.println(input);
pw.flush();
} catch(Exception e) {
e.printStackTrace();
} finally {
// 5. 통신 종료
try {
if(pw != null) pw.close();
if(br != null) br.close();
if(clientSocket != null) clientSocket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}