반응형
01. 네트워크 입출력
- 프로그램과 프로그램 사이에 값을 보내거나 받는 것
- 주의) 네트워크 프로그램은 여러 클라이언트가 접속할 수 있도록 일부러 무한루프를 발생시켜 이용함!
- TCP 프로토콜 : 서버 & 클라이언트
- UDP 프로토콜 : 주는 사람 & 받는사람
02. 📡 서버가 보내고 클라이언트가 받는 프로그램
- TCP 프로토콜 프로그램1 (소켓프로그램)
- 서버가 보내고 클라이언트가 받는 방법
- 연결형 프로토콜(연결 설정 후 통신 가능)
- 소켓(Socket) 통신 1:1 연결
- 전송 제어 프로토콜(신뢰할 수 있는 데이타 전송에 대한 통신규약)
1) [서버] TimeServerApp
package xyz.itwill.net;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
//서버(serer)란?
// => 외부의 컴퓨터(클라이언트)가 접속할 수 있는 환경과 서비스를 제공하기 위한 컴퓨터 (요청에 대한 응답!!)
// => ex) 웹서버 : html문서를 받아 파싱해서 렌더링하다
//클라이언트(client)란? (복습..)
// => 서버에 접속하여 서비스를 제공받을 수 있는 컴퓨터
//(url주소를 검색한다) = (서버에 접속하겠습니다)
// => 어떤 정보를 주고받기 위해서는 접속하는 행위가 필요
// => 접속하는 행위를 주는 컴퓨터가 바로 서버 컴퓨터!!!
// => ex) NTP(Network Time Protocol) Server : 날짜와 시간을 제공하는 서버 컴퓨터
//접속된 클라이언트에게 서버 컴퓨터의 현재 날짜와 시간을 전달하는 서버 프로그램
//=> NTP(Network Time Protocol) Server : 날짜와 시간을 제공하는 서버 컴퓨터
public class TimeServerApp {
public static void main(String[] args) {
//🔥🔥🔥 ServerSocket클래스 : 네트워크에서 서버 프로그램을 만들기 위해 사용하는 클래스
// => ServerSocket(int port : 포트번호를 전달받아 ServerSocket 객체를 생성하는 생성자
// => ServerSocket 객체를 생성하였다 = 클라이언트가 접속할 수 있는 환경을 제공해주었다(포트를 열어줌)
//=> 만약 전달받은 포트번호를 이미 다른 네트워크 프로그램에서 사용 중인 경우 IOException 발생
//1.🔥
//ServerSocket 객체 생성
ServerSocket ntpServer = null;
try {
//ServerSocket 객체 생성해 2000 포트가 활성화됨 - 클라이언트가 접속할 수 있는 환경 세팅
ntpServer = new ServerSocket(2000); //2000번 포트 활성화
//ServerSocket.toString() : ServerSocket객체에 저장된 접속 관련 정보를 문자열로 변환하여 반환하는 메소드
// => 이제 모든 컴에서 2000번 포트을 통해 접근 가능하다!
System.out.println("ntpServer ="+ ntpServer);
//ntpServer =ServerSocket[addr=0.0.0.0/0.0.0.0,localport=2000]
System.out.println("[메세지]NTP Server Running...");
//2.
//서버 프로그램에 다수의 클라이언트 접속을 허용하도록 무한반복 사용
// => 서버는 일부러 무한루프를 빠트려 다수의 클라가 서버에 접속해 서비스를 제공받도록 함
// => 계속 클라를 기다리는 서버.. >> 한 클라가 들어오면 정보 제공 >> 소켓 끊음 >> 또 다른 클라 기다림 >> 정보 제공 >> 소켓 끊음.. 반복
while(true) {
//2-1.
//ServerSocket.accept() : 클라이언트의 접속을 기다리는 메소드
// => (🎩일시중지) : 클라이언트가 접속되기 전까지 🎩메인스레드는 계속 일시 중지
// => (🎩실행) : 클라이언트가 접속하면 클라이언트의 소켓과 연결될 소켓(Socket 객체)를 생성하여 반환하고 스레드는 실행됨
// => Socket : 클라이언트와 연결된 Socket 객체 생성됨
Socket socket = ntpServer.accept();
//2-2.
//Socket.toString() : Socket 객체에 저장된 접속 관련 정보(접속 호스트 및 포트와 로컬호스트 및 포트)을 문자열로 반환하는 메소드
System.out.println("socket = "+socket); //클라이언트 접속 시 출력됨
//socket = Socket[addr=/192.168.13.11,port=50228,localport=2000]
//2-3.
// => 소켓에게 날짜와 시간 정보를 보내주세요~ (출력스트림 이용)
// => (메소드) socket.getOutputStream() 원시데이타 출력스트림
// => (확장) new ObjectOutputStream(socket.getOutputStream()) 객체 출력스트림
/*
//💚방법1.
//Socket.getOutputStream(): Socket객체의 출력스트림(OutputStream 객체)을 반환하는 메소드
OutputStream out = socket.getOutputStream();
//OutputStream 객체를 전달받아 객체 전달이 가능한 ObjectOutputStream 객체로 출력스트림 확장
ObjectOutputStream stream = new ObjectOutputStream(out);
//시스템의 현재 날짜와 시간이 저장된 Date 객체 생성
Date now = new Date();
//출력스트림을 이용하여 Date 객체 전달 - 클라이언트에게 날짜와 시간 전송
stream.writeObject(now);
*/
//or
//💚방법2. - 빠르게작성
//불필요한 참조변수를 없애고 원하는 기능만 구현되게 한줄 작성!
new ObjectOutputStream(socket.getOutputStream()).writeObject(new Date());
//2-4.
//⭐중요 - 서버 로그 처리는 반드시!!!
// => 로그 처리 - 기록 (서버가 일하고 있는 것을 기록으로 남긴다.)
// => 원래는 파일 기록하겠지만 일단은 System.out.println()으로 출력하자!
// => Socket.getInetAddress() : 소켓으로 연결된 외부 컴퓨터의 네트워크 정보(InetAddress 객체)를 반환하는 메소드
// => Socket.getHostAddress() : 소켓으로 연결된 외부 컴퓨터의 IP주소를 반환하는 메소드
System.out.println("[정보]클라이언트["+socket.getInetAddress().getHostAddress()+"]에게 날짜와 시간을 제공 하였습니다.");
//[정보]클라이언트[192.168.13.11]에게 날짜와 시간을 제공 하였습니다.
//클라이언트와의 연결 해제
socket.close(); //하나의 클라이언트가 끝나면 다른 클라이언트가 다시 접속하기를 또 기다리는 것! 무한루프
}
} catch (IOException e) {
System.out.println("[에러] 서버 네트워크에 문제가 발생 하였습니다.");
}
}
}
2) [클라이언트] TimeClientApp
package xyz.itwill.net;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
//NTP Server에 접속하여 서버에서 보내온 날짜와 시간을 얻어와 출력하는 클라이언트 프로그램
public class TimeClientApp {
public static void main(String[] args) throws ClassNotFoundException {
//🔥🔥🔥Socket클래스: 'TCP' 프로그램에서 다른 컴퓨터와 연결을 위한 정보를 저장하기 위한 클래스
// => Socket(String host, int port) : 호스트(혹은 IP Address 작성)와 포트를 전달하여 서버 컴퓨터에 접속한 Socket 객체를 생성하는 생성자
// => UnknownHostException 또는 IOException 발생 - 일반 예외이므로 반드시 예외처리
// => Socket 객체에는 연결된 컴퓨터에 정보를 보내거나 받을 수 있는 입력 또는 출력 스트림이 자동 생성되어 제공됨
// => socket객체가 있다 = 입출력스트림이 자동적으로 생성된다 (기본적인 자동 제공임)
try {
//1.🔥
//서버와 연결된 Socket 객체 생성
//=> 서버 192.168.13.11 주소의, 2000 포트에 접근하는 Socket객체
Socket socket = new Socket("192.168.13.11", 2000);
//System.out.println("socket ="+ socket);
//socket =Socket[addr=/192.168.13.11,port=2000,localport=51730]
//2.
//Socket.getInputStream() : Socket객체의 입력스트림(InputStream 객체)을 반환하는 메소드
InputStream in = socket.getInputStream();
//3.
//InputStream 객체를 전달받아 객체를 얻어올 수 있는 ObjectInputStream 객체로 입력스트림 확장
ObjectInputStream stream = new ObjectInputStream(in);
//4.
//입력스트림에서 Date 객체를 얻어와 저장
Date date = (Date)stream.readObject(); //ClassNotFoundException Date 클래스가 없을 때 생기는 에러인데, 없을 일이 없으므로 떠넘기기
//5.
//Date 객체에 저장된 날짜와 시간 출력
//방법1.
//System.out.println("[결과]서버에서 제공한 날짜와 시간 = "+ date);
//[결과]서버에서 제공한 날짜와 시간 = Tue Oct 18 13:03:40 KST 2022
//방법2.
System.out.println("[결과]서버에서 제공한 날짜와 시간 = "+ new SimpleDateFormat("yyyy년 MM월 dd일 E요일 HH시 mm분").format(date));
//[결과]서버에서 제공한 날짜와 시간 = 2022년 10월 18일 화요일 13시 08분
//6.
//Socket.close() : Socket 객체를 제거하는 메소드 - 접속해제 (클라이언트가 접속을 끊은것)
socket.close();
} catch (UnknownHostException e) {
System.out.println("[에러]서버 컴퓨터를 찾을 수 없습니다.");
} catch (IOException e) {
System.out.println("[에러]서버에 접속할 수 없습니다.");
}
}
>
}
03. 📡클라이언트가 보내고 서버가 받는 프로그램
- TCP 프로토콜 프로그램2 (소켓프로그램)
- 클라이언트가 보내고 서버가 받는 방법
1) [서버] EchoServerApp
- 서버는 클라가 없다면 아무런 동작 불가능ㅠ
- 클라이언트한테 메세지를 받아보자!! (보내는게 아님)
package xyz.itwill.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
//클라이언트에서 보내온 메세지를 얻어와 출력하는 서버 프로그램
public class EchoServerApp {
public static void main(String[] args) {
//1.🔥
//ServerSocket 객체 생성
ServerSocket echoServer = null;
try {
//1.🔥
//3000포트가 활성화됨 ( 클라이언트야 3000포트로 들어와~)
echoServer = new ServerSocket(3000);
System.out.println("[메세지]Echo Server Running...");
//2. 다수의 클라이언트 접속 허용
while(true) {
//2-1.
//🎩클라이언트의 접속 기다리다가 클라이언트가 접속하면 Socket객체 생성해 반환해줄것임
Socket socket = echoServer.accept();
//2-2.
//Socket 객체의 입력스트림을 반환받아 대량의 문자데이타(Buffered덕분)를 읽을 수 있는 입력스트림으로 확장
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//2-3.
//BufferedReader.readLine() : 문자열 읽을 때 쓰는 메소드~
// => 클라이언트에서 보내온 메세지를 읽어와 출력
// => 🎩클라이언트에서 메세지를 보내기 전까지 스레드 일시 중지
System.out.println("["+socket.getInetAddress().getHostAddress()+"]님이 보내온 메세지 = " + in.readLine());
//[192.168.13.11]님이 보내온 메세지 = 잘 가나
//2-4.
socket.close();
}
}catch (IOException e) {
System.out.println("[에러]서버 네트워크에 문제가 발생 하였습니다.");
}
}
}
2) [클라이언트] EchoClientApp
package xyz.itwill.net;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
//키보드로 메세지를 입력받아 접속 서버에 전달하는 클라이언트 프로그램
// => 키보드입력스트림 : 메세지입력받음
public class EchoClientApp {
public static void main(String[] args) throws IOException {
//1.🔥
//키보드 입력스트림을 대량의 문자데이타(문자입력InputStreamReader -> 문자열입력BufferedReader)를 입력받을 수 있는 입력스트림으로 확장
//입력스트림생성
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println("전달 메세지 입력 >> ");
//2.
//대량의 문자데이타(문자열)로 읽음
String message = in.readLine();
try {
//3.🔥
//Socket 객체 생성함 = 서버에 접속함
Socket socket = new Socket("192.168.13.11",3000);
//4.
/*
//방법1.
//소켓의 출력스트림을 반환받아 '대량의 문자데이타(문자열)'를 '전달'할 수 있는 출력스트림으로 확장
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//출력스트림을 이용하여 서버에 문자열(메세지) 전달
// => 출력스트림으로 보내지 않고 출력버퍼에 저장 >> 일정 크기가 되면 출력스트림으로 전달
// => 파일처리 빼고'writer'는 문자데이타를 출력스트림으로 보내지않고 출력버퍼에 저장하려는 성질을 가짐
out.write(message);
//💧출력버퍼에 존재하는 문자데이타를 출력스트림으로 전달
out.flush();
//접속해제
socket.close();
*/
//OR
//방법2.
//소켓의 출력스트림을 반환받아 '모든형식의 값'을 전달할 수 있는 출력스트림으로 확장
PrintWriter out = new PrintWriter(socket.getOutputStream());
//PrintWriter.println(Object o) : '모든 형식의 값'을 문자열로 처리하여 출력스트림으로 '전달'하는 메소드
out.println(message);
//💧출력버퍼에 존재하는 문자데이타를 출력스트림으로 전달
out.flush();
//접속해제
socket.close();
} catch (IOException e) {
System.out.println("[에러]서버에 접속할 수 없습니다.");
}
}
}
반응형
'java > java.net' 카테고리의 다른 글
[java.net] 5. 채팅 서버 프로그램 | 채팅 클라이언트 프로그램 (0) | 2024.07.03 |
---|---|
[java.net] 4. UDP 프로토콜 프로그램 (0) | 2024.07.03 |
[java.net] 2. IPAddress 클래스 | ServerSocket 클래스 (0) | 2024.07.02 |
[java.net] 1. 프로토콜의 구조 (0) | 2024.07.02 |