-
자바 네트워크 네트워크 입출력 (1) - TCP언어/JAVA 2023. 8. 22. 19:19
1. 네트워크 기초
- 네트워크는 여러 컴퓨터들을 통신 회선으로 연결하는 것
- LAN은 가정,회사,건물,특정 영역에 존재하는 컴퓨터 연결
- WAN은 LAN을 연결한 것이다. (WAN이 흔히 말하는 인터넷이다)
- LAN과 LAN을 라우터가 연결
- 라우터와 LAN은 스위치로 연결
1.2 서버와 클라이언트
- 네트워크에서 유무선으로 컴퓨터가 연결되어 있다면, 실제로 데이터 주고받는 행위는 프로그램들이 한다.
- 서비스를 제공하는 프로그램을 서버, 서비스 요청하는 프로그램을 클라이언트라 부른다.
- 인터넷을 통해서 두 프로그램이 통신하기 위해서는 클라이언트가 서비스 요청, 서버는 처리 결과 응답으로 제공한다.
1.3 ip주소
- 컴퓨터의 고유주소이다. 컴퓨터마다 받는 것이 아니라, 네트워크 어답터(LAN 카드)마다 할당
- 두개의 어댑터가 연결되어 있다면, 두 개의 IP주소를 할당받을 수 있다.
- 연결할 상대의 IP주소도 알아야 통신할 수 있다.
- 프로그램은 DNS서버를 이용해서 컴퓨터 IP 주소를 검색한다.
- DNS는 도메인 이름으로 IP를 등록하는 저장소이다.
- 웹 브라우저는 웹 서버와 통신하는 대표적인 클라이언트 프로그램으로, 사용자가 입력한 도메인 이름으로 DNS서버로 ip주소를 검색해서 웹서버와 연결해서 웹 페이지를 받는다.
* 윈도우 ip설정에 보면, DNS와 ip주소는 자동으로 부여된다. (Switch가 알아서 자동 생성)
동일한 컴퓨터는 대부분 같은 ip를 부여받는데, 이는 switch가 pc의 물리적 주소로(Map address) 구분할 수 있기 때문이다. (어뎁터, LAN카드별 고유 식별번호)
*네트워크 통신을 위해서는 외부 IP도 필요하다 (LAN과 LAN, 라우터 IP 등 인터넷상에서 사용하는 IP필요)
* ip주소나 DNS서버는 네트워크 관리자로부터 받아온다. -> 집에 있는 네트워크 장비는 대부분 스위치로 이를 통해서 자동으로 부여받은 것
1.4 Port번호
- 한대의 컴퓨터에 다양한 서버 프로그램이 실행될 수 있다.
- 클라이언트는 서버 ip뿐 아니라, 서버 프로그램에 할당된 port번호도 알아야 연결될 수 있다.
- port는 운영체제가 관리하는 서버 프로그램의 연결 번호이다. 서버는 특정 포트번호에 바인딩한다.
- 클라이언트도 서버에서 보낸 정보를 얻기 위해선 port가 필요한데, 서버 처럼 고정적인 port번호에 바인딩 되는 것이 아니라, 운영체제에 의해 자동으로 부여되는 번호 사용한다.
- 클라이언트 포트번호는 서버로 요청을 보낼 때 함께 전송되어 서버가 클라이언트로 데이터 보낼 때 사용된다.
2. IP주소 얻기
- 자바는 IP주소를 InetAddress로 표현한다.
- 이를 통해 local, 외부, DNS를 통한 ip를 얻을 수 있다.
public class IPget{ public static void main(String[] args){ try{ //로컬 ip얻기 InetAddress local = InetAddress.getLocalHost(); InetAddress[] iaArr = InetAddress.getAllByName("www.naver.com"); for(InetAddress remote : iaArr){ //.. } }catch(Exception e){ } } }
3. TCP 네트워킹
- IP주소로 프로그램들이 통신할 때는 약속한 데이터 전송 규약이 있다. 이를 전송용 프로토콜이라고 부른다.
- 인터넷 전송용 프로토콜은 TCP,UDP가 있다.
- TCP는 연결형 프로토콜, 상대방이 연결된 상태에서 데이터 주고 받음
- 서버가 연결을 수락하면 통신 회선이 고정되고, 데이터는 고정 회선을 통해 전달됨
- TCP는 보낸 데이터가 순서대로 전달되며 손실이 발생하지 않는다.
- TCP는 웹 브라우저(클라이언트 프로그램)가 웹 서버에 연결할 때 사용된다.
- TCP 네트워킹을 위해 ServerSocket과 Soket 클래스를 제공한다.
- ip/port는 컴퓨터와 프로그램 구분하기 위한 번호
- 실제 연결, 데이터 전송은 Soket을 사용
- 클라이언트에서 서버로 요청을 보내면 서버소켓이 이를 받고, 소켓을 생성 서버에서 생성된 소켓을 통해 통신한다.
3.1 TCP서버
- 서버소켓 생성
ServerSocket serverSocket = new ServerSocket(50001); //서버소켓 생성 후에 바인드 ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress(50001)); // 여러 개의 ip가 컴퓨터에 할당되어 있는 경우, 특정 ip에서만 서비스하고 싶을 때 ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress("ip주소",50001));
- 만약 Port 이미 다른 프로그램에서 사용 중이라면 BindException이 발생
Socket socket = serverSocket.accept();
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress(); String clientIp = isa.getHostName(); String protNo = isa.getPort(); //소켓 종료 serverSocket.close();
- 서버 프로그램
public class TCPServerExam { private static ServerSocket serverSocket; public static void main(String[] args) { System.out.println("---------------------------------"); System.out.println("서버를 종료하려면, q 혹은 Q 입력하고 Enter를 입력하셔요"); //TCPServer시작 startServer(); Scanner sc = new Scanner(System.in); while(true){ String input = sc.nextLine(); if(input.toLowerCase().equals("q")) { break; } } sc.close(); //서버종료 stopServer(); } public static void startServer(){ //작업스레드 정의 Thread thread = new Thread(){ @Override public void run(){ //서버소켓+바인딩 try { serverSocket = new ServerSocket(50001); System.out.println("서버시작"); while(true){ //여러 클라이언트 연결요청받기 위해 계속 기다림 //하나의 소켓은 하나의 연결요청 기다림 System.out.println("[서버] 연결요청을 기다림\n"); Socket soket = serverSocket.accept(); InetSocketAddress isa = (InetSocketAddress)soket.getRemoteSocketAddress(); System.out.println("[서버]"+isa.getHostString()+"와 연결 요청 수락"); //포트번호는 뭐 별거아닌데, ip주소는 중요한 의미가 있음! 따라서 //ip주소는 저장할 필요가 있다. 중요함 서버입장에서 //연결끊기 soket.close(); //서버소켓과 마찬가지로 종료해줘야함 단, 서버나 클라이언트 소켓 둘중하나만 끊어도됨 System.out.println("[서버]"+isa.getHostName()+"와 연결 끊음"); } } catch (IOException e) { System.out.println(e.getMessage()); //소켓익셉션은 io익셉션임 //accept() 때문에 있음 서버소켓 종료시 } } }; thread.start(); } public static void stopServer(){ try { serverSocket.close(); } catch (IOException e) { } } }
*서버소켓을 생성하고 accept()하는 부분은 쓰레드로 처리해야한다. 이는 서버를 키고 끄는 것과 서버에서 클라이언트 요청 받는 것 동시에 진행되야해서그렇다.
- TCP 클라이언트
Socket socket = new Socket("서버ip",포트번호); Socket socket = new Socket(new InetAddress.getByName("domainName",포트번호));
- 연결 요청시 두 가지 예외가 발생할 수 있다. UnknownHostException은 ip 주소나 port번호가 잘못 표기
- IOException 제공된 IP와 Port번호로 연결할 수 없을 때 발생
try{ Socket socket = new Socket("서버ip",포트번호); }catch(UnknownHostException e){ }catch(IOException e){ }
- 클라이언트 프로그램
public class TCPClientExam { public static void main(String[] args) { try { //socket 열기 생성동시에 연결요청 Socket socket = new Socket("localhost",50001); System.out.println("[클라이언트]연결성공"); //socket닫기 socket.close(); System.out.println("[클라이언트] 연결종료"); } catch (UnknownHostException e) { //IP나 포트 표기방법 틀림 System.out.println("UnknownEx = "+e.toString()); }catch (IOException e){ //ip나 포트 없음 System.out.println("ioEx = "+e.toString()); } } }
> 입출력 스트림으로 데이터 주고 받기
- 클라이언트 연결 요청을 하고 서버가 연결 요청을 수락했다면, Socket을 통해 입출력 스트림을 얻을 수 있다.
InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); //데이터 쓰기 S;tring data = "보낼데이터" byte[] bytes = data.getBytes("UTF-8"); os.write(bytes); os.flush(); //데이터 쓰기 with DataOutputStream DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); dos.writeUTF(bytes); dos.flush(); //데이터 읽기 byte[] bytes = new byte[1024]; int count = is.read(bytes); String message =new String(bytes,0,count,"UTF-8"); //데이터 읽기 with DataInputStream DataInputStream dis = new DataInputStream( socket.getInputStream()); String data = dis.readUTF();
- 클라이언트
try { //.. //데이터보내기 with 일반 String message = "나는 잡아가 조아"; byte[] bytes = message.getBytes("UTF-8"); OutputStream os = socket.getOutputStream(); os.write(bytes); os.flush(); System.out.println("[클라이언트] 메시지 보냄"+message); //데이터 받기 with 일반 InputStream is = socket.getInputStream(); bytes = new byte[1024]; int count = is.read(bytes); String recivemessage = new String(bytes,0,count,"UTF-8"); System.out.println("[클라이언트] 메시지 받음 "+recivemessage); //데이터 쓰기 // String message = "나는 잡아가 조아"; // DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); // dos.writeUTF(message); // dos.flush(); //데이터 읽기 // DataInputStream dis = new DataInputStream(socket.getInputStream()); // String message = dis.readUTF(); //.. }
-서버
//서버연결 //.. //데이터 받기 (기본 inputStream) InputStream is = soket.getInputStream(); byte[] bytes = new byte[1024]; int readByteCount = is.read(bytes); String message = new String(bytes,0,readByteCount,"UTF-8"); //데이터 보내기(기본 output) OutputStream os = soket.getOutputStream(); bytes = message.getBytes("UTF-8"); os.write(bytes); os.flush(); System.out.println("[서버] 받은 데이터 다시 보냄 "+message); //데이터읽기 // DataInputStream dis = new DataInputStream(soket.getInputStream()); // String message = dis.readUTF(); //데이터보내기 // DataOutputStream dos = new DataOutputStream(soket.getOutputStream()); // dos.writeUTF(message); // dos.flush(); //연결 해제 socket.close();
참고자료: 이것이 자바다 (신용권,임경균)
'언어 > JAVA' 카테고리의 다른 글
자바스터디(1) (0) 2023.10.18 쓰레드 기본 (0) 2023.08.25 Java - 일급컬렉션 (0) 2023.07.25 Servlet-JSP MVC07 파일 수정하기 (0) 2023.07.24 Java - File클래스 (0) 2023.07.24