전 세계적으로 연결되어있는 물리적인 네트워크 망
하나의 컴퓨터가 있으면 다른 컴퓨터가 데이터 통신을 주고받으려면 LAN WAN(무선, 유선)이든 네트워크를 연결해야한다. 물리적인 저장장치로 통신을 하기 위해서 하나의 단위로 묶는 것
네트워크를 크기 단위로 쪼갠 것
상대방 컴퓨터의 IP 주소를 알아야한다
IP는 논리적인 주소라서 변경이 가능하다
물리적인 주소는 실제 제품에 주솟값이 찍혀져 있는 것이다
정확히는 RAM카드 뒤쪽에 보면 MAC이라는 유일한 주솟값이 찍혀져 있다
통신할때는 IP주소를 사용하지만 정확한 주소는 MAC주소로 바뀌어서 통신하게 된다
IP → MAC으로 누가 어떻게 바꿀까? ARP
1. HTTP Protocol
웹서버와 웹브라우저끼리 사용하는 통신규칙
2. FTP Protocol
두개의 컴퓨터가 파일단위로 어떻게 통신을 할지 정한 규칙
3. SMTP Protocol
4. TCP/IP
통신을 하기 위해서는 IP주소, 프로토콜, 포트가 필요하다
컴퓨터에 들어갈 IP 주소를 알아야하고 컴퓨터 내부에 들어있는 프로세스의 주소 포트를 알아 어떻게 통신을 할지 프로토콜을 알아야 통신이 가능하다
구현해야 하는 과정
1. 서버프로세스는 서버 소켓 생성(클라이언트의 접속을 받아들여서 소켓을 만드는일을함)
2. 만들어진 소켓을 가지고 클라이언트 프로세스가 ip, 포트번호를 가지고 접속시도
3. 접속이 확인되면 서버프로세스의 서버 소켓이 클라이언트와 통신하기 위한 용도의 소켓을 하나더 만든다(소켓끼리 연결)
4. 두개의 소켓을연결할 inputStream, outputStream 을 매핑하여 2개씩 만들어 데이터를 주고받을 수 있도록 해야한다
public class Exam01_DateClient extends Application {
TextArea textArea; //텍스트 입력가능한 곳
Button connBtn; //버튼생성
@Override //추상메소드 오버라딩
public void start(Stage primaryStage) throws Exception {
// 화면 구성
BorderPane root = new BorderPane();
root.setPrefSize(700,500); //window 크기
textArea = new TextArea();
root.setCenter(textArea); //화면 센터에 textarea 를 붙인다
connBtn = new Button("Date 서버 접속"); ///접속 버튼 만듬
connBtn.setPrefSize(150,40);
connBtn.setOnAction(e ->{
textArea.clear();
try {
//서버 process 에 접속을 시도 (ip, port에 접속할겁니다!)
Socket socket = new Socket("localhost",5678);
//접속에 성공했으니 이제 stream을 열자
InputStreamReader ir = new InputStreamReader(socket.getInputStream());
//스트림을 결합하여 가장 사용하기 편한 형태로 변신
BufferedReader br = new BufferedReader(ir);
String msg = br.readLine(); //blocking 메소드이다 - 읽을수 있는게 들어올때까지 대기 (서버가 보내주지 않으면)
textArea.appendText(msg + "\n"); //받은 메세지를 화면에 붙여준다
br.close();
ir.close();
socket.close();
textArea.appendText("서버와의 연결이 종료되었습니다");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
});
FlowPane flowPane = new FlowPane(); //판 하나 만드는것
flowPane.setPadding(new Insets(10,10,10,10)); //판 위에 여백을 준다
flowPane.setHgap(10);
flowPane.getChildren().add(connBtn); //버튼을 붙인다
root.setBottom(flowPane); //아래에 플로우팬을 붙인다
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
//스레드 생성하면서 창을 띄운다
launch();
}
}
public class Exam01_DateServer {
public static void main(String[] args) {
try { //뒤쪽에 임의로 내가 포트번호를 적어준다
ServerSocket serverSocket = new ServerSocket(5678);
System.out.println("Date Server 기동 - 5678");
//클라이언트 소켓에 담는다
Socket socket = serverSocket.accept(); //5678을 가지고 클라이언트를 기다려!(blocking)
//접속에 성공했어요! printWriter => 조금더 나은형태의 데이터 스트림 - 문자열을 더 쉽게 보낼 수 있다
PrintWriter pr = new PrintWriter(socket.getOutputStream());
//현재 날짜를 구한다
Date date = new Date();
//만들어진 스트림으로 데이터를 보낸다
pr.println(date.toString());
/**
버퍼에 들어가 있는 데이터를 스트림을 통해 내보내는 시점은
1. 스트림이 강제로 종료될 경우
2. 버퍼의 공간이 다 찰 경우
3. method 를 이용해서 flush() 시킬 경우 -> 가능하면 3번으로 사용하기
**/
//역순으로 사용한 리소스 닫기
// pr.close(); 보다 plush 사용하기
pr.flush();
socket.close();
serverSocket.close();
System.out.println("Date Server 종료");
} catch (IOException e) { //자바의 특정 코드들은 try-catch 가 강제되는 코드들이 있다
}
}
}
코드 설명
- javaFx로 구현한 부분을 제외한 형광펜 부분이 통신을 진행하는 구현 코드이다
- 분홍색에 체크한
connBtn.setOnAction
을 수행하면- [서버] 서버단에서 최초의 ServerSocket을 만든다 (포트번호)
- [서버]
serverSocket.accept()
를 사용하여 클라이언트가 올때까지 기다린다.- [클라이언트] 클라이언트 역시 소켓을 생성
최초의 ServerSocket이 클라이언트와 연결(통신)되면 바로 서버와 클라이언트 각각에 소켓이 생성됨
값을 읽기위한 input 스트림을 생성한다 BufferdReader형태로 값을 읽기위한 편한 형태로 만들어주기- [클라이언트]
br.readLine()
는 읽을 값이 들어오기까지 기다린다- [서버] 클라이언트와 마찬가지로 데이터를 보낼 stream 통로를 만든다 날짜를 보내주기 위한 로직 생성
- [클라이언트] 에서 이용자가 값을 입력하고 버튼을 누르면 위의 과정이 실행되어 결과값으로 현재 시간을 보내준다!
public class Exam02_EchoServer {
public static void main(String[] args) {
//서버소켓 선언
ServerSocket serverSocket = null;
Socket socket = null;
PrintWriter pr = null;
BufferedReader br = null;
try {
serverSocket = new ServerSocket(5678);
System.out.println("Echo Server 기동 - 클라이언트 접속 대기");
//클라이언트 소켓에 담는다
socket = serverSocket.accept(); //5678을 가지고 클라이언트를 기다려!(blocking)
//접속에 성공했어요! printWriter => 조금더 나은형태의 데이터 스트림 - 문자열을 더 쉽게 보낼 수 있다
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pr = new PrintWriter(socket.getOutputStream());
/**클라이언트가 exit 보내기 전까지 반복해서 읽고 보내는 작업을 제작*/
String msg = null;
while(true){
msg = br.readLine();
//문자열비교는 equals
//클라이언트가 그만 입력 || 창 강제 종료 시킬 경우
if (msg.equals("/exit") || (msg == null)){
break;
}
//제대로 값 도착할 경우 - 데이터를 그대로 보냄
pr.println(msg);
pr.flush(); //buffer를 기반으로 했기 때문에 원하는 데이터를 제대로 안보내줄 수 있다
}
} catch (IOException e) { //자바의 특정 코드들은 try-catch 가 강제되는 코드들이 있다
}finally {
//finally -> try~ 오류가 있던 없던 무조건 수행
// 사용된 resource 를 해제
try {
if (br != null) br.close();
if (pr != null) pr.close();
if (socket != null) socket.close();
if (serverSocket != null) serverSocket.close();
System.out.println("Echo Server 종료!!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
public class Exam02_EchoClient extends Application {
TextArea textArea; //텍스트 입력가능한 곳
Button connBtn; //버튼생성
TextField idField, textField;
Socket socket;
BufferedReader br;
PrintWriter pr;
@Override //추상메소드 오버라딩
public void start(Stage primaryStage) throws Exception {
// 화면 구성
BorderPane root = new BorderPane();
root.setPrefSize(700,500); //window 크기
//가운데 글상자
textArea = new TextArea();
root.setCenter(textArea); //화면 센터에 textarea 를 붙인다
connBtn = new Button("echo 서버 접속"); ///접속 버튼 만듬
connBtn.setPrefSize(150,40); //버튼의 크기
connBtn.setOnAction(e -> {
textArea.clear();
try {
socket = new Socket("localhost", 5678);
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pr = new PrintWriter(socket.getOutputStream());
textArea.appendText("Echo 서버 접속 성공!!" + "\n");
} catch (Exception e2) {
}
});
//아이디입력
idField = new TextField();
idField.setPrefSize(100, 40);
textField = new TextField();
textField.setPrefSize(200,40);
textField.setOnAction(e -> {
//보낼 문자열 만들기
String msg = idField.getText() + " : " + textField.getText();
pr.println(msg);
pr.flush();
//텍스트 입력한게 /exit 인지 일반 메세지인지 판단
if (textField.getText().equals("/exit")){
textArea.appendText("서버와의 연결을 종료합니다");
textField.setDisable(true); //disable를 true로 세팅한다 = 사용자 입력이 안되도록 조치
}else{
try {
String serverMsg = br.readLine();
textArea.appendText(serverMsg + "\n");
}catch (Exception e2){
}
}
textField.clear();
}); //입력상자에 글 입력 후 enter 입력하면 이벤트 처리가 된다
FlowPane flowPane = new FlowPane(); //판 하나 만드는것
flowPane.setPadding(new Insets(10,10,10,10)); //판 위에 여백을 준다
flowPane.setHgap(10);
flowPane.getChildren().add(connBtn); //버튼을 붙인다
flowPane.getChildren().add(idField);
flowPane.getChildren().add(textField);
root.setBottom(flowPane); //아래에 플로우팬을 붙인다
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
//스레드 생성하면서 창을 띄운다
launch();
}
}
코드 설명
- javaFx로 구현한 부분을 제외한 형광펜 부분이 통신을 진행하는 구현 코드이다
- [서버]에서는 위의 과정과 마찬가지로 ServerSocket과 socket을 만든다. 여기서 socket은
accept()
를 사용하여 클라이언트가 올때까지 기다리도록 한다- [클라이언트]에서는 크게 두가지로 나뉘어진다
주황색 형광팬이 그려진 사각형은 버튼을 누를 경우 Stream input, output이 모두 생성되도록 만들었다
최초의 버튼이 눌려야 스트림이 생성되고 서버와 연결이된다!- [서버]
/exit
문자열이 나오기 전까지는 무한 반복을 하기위해 while(true)로 제어문을 만든다
read.Line()
으로 클라이언트로부터 읽을 값이 들어오기 전까지는 멈추도록 함. 그뒤 특정 문자열이 아니면 들어온 값을 그대로 찍어서 다시flush()
로 보낸다- [클라이언트] 입력한 문자열을
flush()
를 사용해 서버에게 보낼수 있도록 함. 입력한 값이 키워드와같으면 종료를 하도록 하고 아닐 경우에는 서버에서 보내는 값이 올때까지 대기하도록 한다
- 해당과정을 키워드
/exit
가 올때까지 반복