서버 클라이언트
TCP => ServerSocket / Socket
UDP => DatagramSocket / DatagramPacket
< TCP 방식 > ( 기본 사용 )
- 양방향 스트림 전송 서비스
- 전화 (연결-통신-해제)
=> 순차적인 순서에 의해서 내용이 전달됨
=> 동기화 / 전화하듯, 연결되어 있는 동안 다른데서 사용 불가능
=> 다수의 클라이언트에게 다수의 요청이 들어오면 TCP 만 사용할 시 순차진행이 되므로 후에 들어온 요청들은 주구장창 대기해야한다.
=> 웹서비스에서 TCP는 사실상 거의 멀티쓰레드로 구현해서 사용한다. => 다수의 쓰레드사용 ㅡ 요청 동시처리 가능 (스레드풀/MAX스레드/WAS/Sevlet)
- TCP : 신뢰성 안정성 필요할 때 사용
- 서버,클라이언트간의 신뢰성 있는 통신 보장
- 패킷에 대한 연결제어 ( 흐름제어, 오류제어, 혼잡제어 ) 제공
=> 클라-서버 연결전에 syn, ack을 이용해 연결의사를 확인할 수 있음
해제시에도 fin 을 통해 해제의사 확인 => 연결을 관리할 수 있다.
=> 흐름,오류,혼잡제어 가능
- 흐름제어 : 클라-서버간의 생산/소비속도 균형 맞춤 (버퍼사용)
버퍼가 꽉차있으면 안보내기 ( 이 기능이 없으면 계속 버퍼들어와서 유실됨 - 신뢰성X )
- 오류제어 : 주고받는 데이터에 대한 확인 기능 (패킷ack 사용)
데이터 전송후 일정시간동안 이에대한 확인 (ack) 을 받지않으면 데이터를 다시보냄
- 혼잡제어 : 클라-서버간 버퍼사이즈 조절 => 네트워크 혼잡 방지 ( 라우터 혼란 방지 )
< TCP 방식 순서 >
Server Client
1. 서버시작
2. 클라이언트 접속대기
3. 서버접속
4. 클라 접속허용
5. 요청
6. 응답
7. 서버 접속 해제
8. 클라 접속 해제 => 2.반복 while(true)
- 처음에 연결 할때만 번호 필요
=> 통신 할때는 내용만 주고 받음 (처음 이후에는 5-6 반복)
- Socket : 통신의 양 끝 점 => 모든 통신은 소켓을 통해 이루어진다.
1. 서버시작 => 서버소켓을 만듬
ServerSocket serversocket = new ServerSocket( Port번호 );
( IOException 처리 )
2. ( 서버 대기상태 )
3. 클라이언트도 소켓만들어서 접속
Socket socket = new Socket( "서버ip", 서버port );
4. 서버 => 클라이언트 접속 허용
Socket socket = serversocket.accept( ); => 서버소켓으로 accept - 접속허용
그걸로 클라와의 "연결고리" 소켓 생성
5~6. 요청 - 응답
- 모든 통신은 socket 을 통해 이루어진다.
- 서버와 응답요청 Input Output 순서규칙을 지켜야 진행이 된다
(1) 클라이언트 : 요청보내기 (Output)
OutputStream out = socket.getOutputStream( ); 1바이트 출력
out.write(97); => 'a' // 한글 2BYTE X
- 한글 String 은 어떻게 보내?
=> getByte( ) 해서 바이트로해서 보낸다.
String.getBytes( ); => 2Byte 문자열을 1Byte 배열로 바꿈
byte[ ] b = "Hello자바".getBytes( ); // byte 배열로 리턴한다.
b.length = 9; (1byte * 5 + 3byte*2) //jdk 11은 한글 3Byte로 취급
out.write(("한글스트링").getByte( ));
- 소켓으로 OutputStream 으로 보낼때는, 입력할때 한줄로만 입력이 되기때문에,
읽어들일 때, 스캐너의 nextLine 을 쓰려면 맞게 구별해줘야 한다.
=> \n 의 유무가 매우 중요하다. nextLine을 쓸 경우, \n이 없으면 읽어들이지 못해 오작동
out.write(("한글스트링\n").getByte( ));
- id, pw 와 같이 두 입력값을 Output으로 내보내려면 두번 write 하고,
읽어들일때 스캐너에서 nextLine 등으로 구분해서 읽어들이면 된다.
out.write((id+"\n").getBytes( ));
out.write((pw+"\n").getBytes( ));
String id = sc.nextLine();
String pw = sc.nextLine();
(2) 서버 : 요청읽기 (Input)
InputStream input = socket.getInputStream( );
- 기본적으로 1byte단위로 읽을 수 있음
- 한글String의 경우 => Output에서 .getByte( ) 로 보냈기 때문에,
Byte로 들어오므로 읽어들일 수 있다.
input.read( );
- 읽을때는 편하게 Scanner 등 이용해서 메소드 사용
Scanner sc = new Scanner( input );
String id = sc.nextLine( );
(3) 서버 : 응답 (Output)
- 방식은 똑같다.
OutputStream out = socket.getOutputStream();
out.write(스트링.getBytes());
out.close(); // 응답이 끝나고 더 보낼값이 없으면 닫아준다.
(4)클라이언트 : 응답읽기 (Input)
- 방식은 똑같다.
InputStream input = socket.getInputStream( );
Scanner sc = new Scanner( input );
String from_Server = sc.nextLine( );
=> 리팩토링
Scanner sc = new Scanner( socket.getInputStream( ) );
String from_Server = sc.nextLine( );
System.out.println("서버응답 : " + from_Server);
7. 클라 서버접속 해제 socket.close( );
8. 서버도 클라접속 해제 socket.close( ); => 다시 대기상태
<TCP> 소켓생성 - 요청 - 응답
서버소켓생성(포트) ㅡ 클라 소켓생성(IP/포트) ㅡ 서버에서 클라소켓 accept하면서 서버도 소켓생성 ㅡ 연결고리완료 ㅡ 클라 요청output ㅡ 서버 요청읽기Input ㅡ 서버 응답 output ㅡ 클라 응답읽기 Input ㅡ close
< UDP 방식 > ( 필요시 사용 ) 우편
- 데이터 주고받을 때, 항상
( 내용 + 보낸사람 + 받는사람 ) 세트로 보낸다.
- 응답이 없는 구조에 적합 ( 일방적 전달 - 공지사항 )
- 대량의 data 보낼 때 적합 (속도 빠름)
- 순차적 처리(X) - 요청 처리순서가 정해져있지 않음
- 연결제어( 흐름/오류/혼잡 ) 기능 제공 X
=> 사전 연결 불필요 - 속도 빠르다, 빠른 통신 가능
=> 신뢰성 보장 X ( 어플 layer 에서 신뢰성보장 장치구축 필요 )
- UDP : 신뢰성은 없지만 빠른처리 필요할 때 사용
( UDP 에 신뢰성 장치 달면 속도 + 신뢰성 가능 (HTTP3) )
- UDP 방식 : "응답" 없이 일방적인 전송
=>단순하게 send => receive 끝
- DatagramPacket => 알맹이
=> ( 내용(Byte단위) + 길이 + 받는컴퓨터 ip/port )
- DatagramSocket => 연결고리
=>메소드 딱 두개
Socket.send( DatagramPacket )
Socket.receive( DatagramPacket )
=> 보내는건 소켓으로 / 안에 든 알맹이는 무조건 Packet 만 들어감
< UDP 방식 순서 >
- 모든 전송은 Socket 을 통해서 이루어진다.
- 기본적으로 1Byte 단위 전송
- 한글String 보낼 땐, getByte( ) 쪼개서 보낸다.
- 읽어올땐 Scanner 없이 Packet 을 읽어오기 때문에
=> Byte로 들어온걸 getData( ) 를 이용해 받는다.
1. Receiver 받기
- 먼저 시작 (준비상태 - 받는 IP/Port 준비)
=> 준비 되어있어야 보낼 수 있다.
(1) 연결고리 생성하고 / 포트 지정하고
DatagramSocket Receiver = new DatagramSocket( 포트15000 );
(2) 얼마나 받을지 지정 ( Byte 배열 만능 )
byte[ ] StringByte = new byte[100];
- 한글까지 포함한 String도 getByte=> byte배열 가능. 나머진 당연히 가능 => byte 배열로 다 받을 수 있음
- 몇 Byte 까지 받을지 지정 [ 100Byte ] => 한글 3byte 취급이니 33글자 정도 받겠다.
(3) Packet 에 받을 내용 담기
DatagramPacket packet = new DatagramPacket( StringByte, StringByte.length );
받을 내용, 내용길이
Receiver.receive( packet ); // 소켓으로 받아오기 => 패킷에 있는걸 receive 해와라!
- getByte( ) 로 한글String => Byte 했다면,
=> receive 할때는 꺼꾸로 String 으로 바꿔줘야 함
=> String 생성자 + getData( ) 사용
String receive_string = new String( packet.getData( ), 0, pack.getLength( ));
패킷내용을 Data로가져오고, 길이지정
( 0 은 offset 상대주소, 0으로 지정)
System.out.println( receive_string );
receiver.close( ); //소켓은 닫아주자.
2. Sender 전송
- Socket => Socket 연결고리
DatagramSocket Sender = new DatagramSocket( );
( 보내는쪽에서는 포트번호를 지정할 필요가 없다. (랜덤포트자동으로 지정됨) )
< 데이터 send 과정 >
---------------------------------------------------------------
String message = "UDP방식으로 보내는 메세지 입니다.";
byte[ ] StringByte = message.getBytes( ); => 내용
( 내용을 Packet 알맹이에 주소와 함께 담아준다. )
DatagramPacket packet
= new DatagramPacket( StringByte, StringByte.length, new InetSocketAddress("192.168.xx.xx", 15000));
내용 , 내용 길이, 받는컴퓨터 IP / 포트번호
Sender.send( packet );
--------------------------------------------------------------
Sender.close( );
- 다른 data를 또 보내고 싶으면, 위에 send 과정을 그대로 다시 실행한다. ( 내용 ㅡ 바이트화 ㅡ 패킷담기 ㅡ send)
=> 매번 ( 내용 + 길이 + ip + port ) 정보 세트로 보내줘야함
- receive 측에서는 =>
반복해서 받을때 따로 반복문을 생성하지 않아도 된다.
( 만들어둔 포트와 리시브 구조가 매번 반복실행)
<UDP> 소켓.send / receive (패킷)
receive 소켓생성(포트) ㅡ receive 양식 정하고(byte배열 [길이] ㅡ 그걸로 패킷생성( 내용, 길이 ) ㅡ 소켓.receive 패킷ㅡ receive는 준비완료 ㅡ send 소켓생성(자동 포트) ㅡ 보낼 데이터 byte화 하고 ㅡ 포켓에 담기( 내용, 길이, 받을 IP/포트 ) ㅡ 소켓.send 패킷 ㅡ close
'Back to the Java' 카테고리의 다른 글
.equals( ) 메소드 override => 객체 비교하기 (0) | 2023.01.11 |
---|---|
객체지향 활용하기 (0) | 2023.01.10 |
Net 클래스 / 네트워크/ IP/Port / InetAddress 클래스 / (0) | 2022.07.11 |
File 클래스 => 파일/디렉토리 정보제공 (0) | 2022.07.08 |
파일 입출력 클래스 / FileInput/OutputStream / FileReader/FileWriter (0) | 2022.07.08 |