서버 : 서비스를 제공하는 프로그램 또는 컴퓨터
클라이언트 : 서비스를 요청하여 사용하는 프로그램 또는 컴퓨터
- 서버와 클라이언트
네트워크로 연결된 컴퓨터간의 관계를 역할(role)로 구분한 개념
서버는 서비스를 제공하는 프로그램으로 클라이언트의 연결을 수락하고
요청 내용을 처리 후 응답을 보내는 역할
클라이언트는 서비스를 받는 프로그램으로 네트워크 데이터를 필요로 하는 모든 어플리케이션이 해당 됨- IP주소
네트워크 상에서 컴퓨터를 식별하는 번호로 네트워크 어댑터(랜카드)마다 할당 되어 있음- 포트(Port)
같은 컴퓨터 내에서 프로그램을 식별하는 번호로
클라이언트는 서버 연결 요청 시 IP주소와 포트 번호를 알아야 함
- TCP(Transmission Control Protocol)
데이터의 전달의 신뢰성을 최대한 보장하기 위한 방식으로 연결지향형 통신이다.
순차적으로 데이터를 전송하고 확인 및 오류 시 재전송을 한다.- UDP(User Datagram Protocol)
데이터의 빠른 전달을 보장하기위한 방식으로 비연결 지향형 통신이다.
확인 및 재전송 작업이 없다.
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; // 출력용 보조 스트림 변수
//BufferedWriter br = null;
// printWriter에는 print println printf 등 다양한 출력함수를 제공함으로서 파일출력을 편하게 해줌
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();
// ip주소 형태 만들기
System.out.println(clientIP + "가 연결을 요청함...");
//5. 연결된 클라이언트와 입출력 스트림 생성
is = clientSocket.getInputStream(); // clientsocket에서 제공하는 스트림
os = clientSocket.getOutputStream(); // clientsocket에서 제공하는 스트림
//6. 보조 스트림을 통해 성능 개선
br = new BufferedReader(new InputStreamReader(is) );
//InputStreamReader : 바이트 기반 스트림과 문자기반 스트림 연결에 사용하는 스트림
pw = new PrintWriter(os); // 얘는 따로 필요없음
//7. 스트림을 통해 읽고 쓰기
pw.println("[서버 접속 성공]");
pw.flush(); // 스트림에 있는 내용을 모두 밀어냄
// close()도 밀어내는게 가능한데 굳이 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();
}
}
}
}
public class TCPClient {
public void clientStart() {
//1.서버의 IP주소와 서버가 정한 포트번호를 매개변수로 하여 클라이언트용 소켓 객체 생성
int port = 8500;
String serverIP = "127.0.0.1"; // loop back ip(내 컴퓨터를 가리키는 ip)
/*필요한 변수 선언*/
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.print("입력 : ");
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();
}
}
}
}