JAVA/Java 기초

네트워크 기초(IP, TCP, UDP).java

john_ 2023. 1. 31. 18:49
728x90

네트워크

  • 네트워크 : 여러 컴퓨터들을 통신 회선으로 연결한 것
  • LAN(Local Area Network) : 가정, 회사, 건물, 특정영역에 존재하는 컴퓨터 들을 연결 하는것,
    • 근거리 통신 : 스위치, 게이트웨이, 모뎀, 허브, NIC(LAN카드), 브리지
  • WAN(Wild Area Network) : LAN을 연결한 것 = 인터넷
    • 장거리 통신 : 라우터

 


PC에 네트워크 설정

  • IP : pc의 네트워크 연결을 위한 고유 주소
    • 사설 IP : 공유기에서 내부적으로 쓰이는 IP
      • ex) 192.168.x.x
      • 172.16.x.x
      • 10.x.x.x
    • 공인 IP : 실질적인 통신을 위한 IP : 인터넷 연결
      • PC: 사설IP -> 내부 통신간에 사설 IP로 통신, 외부(인터넷)통신 할때는 사설 IP -> 공인 IP로 변환시켜 통신
        • Subnet Mask : 네트워크 영역 확인
          • IP주소에 subnet mask 값을 씌우면 (네트워크 영역 주소) : 네트워크 공유를 할수있는 영역
          • 네트워크 영역 : 내부 통신할 그룹.
  • GateWay : 라우터 장비가 PC로 연결된 인터페이스의 IP 주소
    • 모든 PC는 라우터 장비를 통해서 나갑니다.(Gate Way)
  • DNS(Domain Name Service)  : 도메인(영문)주소를 공인 IP로 변환시켜 주는 서비스
    • KT : 168.126.63.1
    • 구글 : 8.8.8.8

서버와 클라이언트

  • 서버 : 서비스를 제공하는 프로그램
    • 웹서버, DBMS, FTP서버
  • 클라이언트 : 서비스를 요청하는 프로그램
  • 먼저 클라이언트가 서비스를 요청하고, 서버는 처리 결과를 응답으로 제공합니다.

IP주소

  • IP주소 : 네트워크 어댑터 (LAN카드) 마다 할당 되는 컴퓨터의 고유한 주소
    • IP(Internet Protocol) : 인터넷 규약. 형식.
      • IPv4 : 32bit 크기를 가지고 4개부분(옥텟)으로 8bit(0~255) 씩 나누어 사용
        • 192.168.1.1
        • 256.270.109.101 ← 입력 불가 범위값.
        • 232  : 1억
      • IPv6 : 128bit 크기를 16진수로 8개 부분 : 16bit : 16진수 : 4개로 사용
  • ipconfig(윈도우), ifconfig(맥os) 명령어로 네트워크 어댑터에 어떤 IP주소가 부여되어 있는지 확인
  • 프로그램은 DNS를 이용해서 컴퓨터의 IP 주소를 검색합니다.
  • netstat : 네트워크 서비스 상태 보기, port 확

 

 


Port 번호

  • 운영체제가 관리하는 서버 프로그램의 연결 번호.
  • 서버 시작시 특정 port 번호에 바인딩(프로그램에 사용된 구성 요소의 실제 값 또는 프로퍼티를 결정짓는 행위) 됩니다.

 

 


IP주소 얻기

InetAddress

  • 자바는 IP주소를 java.net 패키지의 InetAddress로 표현합니다.
  • 로컬 컴퓨터의 InetAddress를 얻으려면 InetAddress.getLocalHost() 메소드를 호출합니다.
InetAddress ia = InetAddress.getLocalHost();
  • getByName() 메소드는 DNS에서 도메인 이름으로 등록된 단 하나의 IP주소를 가져오고, getAllByName() 메소드는 등록된 모든 IP주소를 배열로 가져옵니다.
  • InetAddress 객체에서 IP주소를 얻으려면 getHostAddress() 메소드를 호출합니다.
String ip = InetAddress.getHostAddress();

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressExam {

	public static void main(String[] args) {

		try {
			InetAddress local = InetAddress.getLocalHost(); // 로컬 PC IP 주소 확인
			System.out.println("내 컴퓨터 IP 주소 : " + local.getHostAddress());
			
			// getAllByName : 도메인 주소를 활용해서 ip 주소 추출
			// 여러 IP 주소가 있을 경우가 있어 배열로 저장합니다.
			InetAddress[] iaArr = InetAddress.getAllByName("www.naver.com");
			
			for(InetAddress remote : iaArr) {
				System.out.println("www.naver.com IP 주소 : " + remote.getHostAddress());
			}
			
		}catch(UnknownHostException e) {
			e.printStackTrace();
		}
	}
}
결과 :
내 컴퓨터 IP 주소 : 172.20.10.17
www.naver.com IP 주소 : 223.130.200.104
www.naver.com IP 주소 : 223.130.195.95

TCP

  • TCP(Transmission Control Protocol) : 신뢰성 있는 통신
    • 신뢰성 : 데이터를 주고 받을때 확인 과정. (패킷 전달간 중간중간 확인)
    • 패킷의 손실을 확인하므로 속도가 조금 느립니다.
    • 데이터를 정확하게 주고받거나 파일을 주고받을때 사용합니다.
  • UDP(User Datagram Protocol) : 비신뢰성 통신
    • 신뢰성 없는 : 데이터를 그냥 뿌려주고 상대방이 잘 받았는지 확인 안함.
    • 중간확인이 없어 속도가 빠릅니다.
    • dhcp 서버 : ip할당
    • 전화, 동영상 스트리밍에 사용합니다.

TCP

  • TCP는 연결형 프로토콜로, 상대방이 연결된 상태에서 데이터를 주고받는 전송용 프로토콜입니다.
  • 클라이언트가 연결 요청을 하고 서버가 연결을 수락하면 통신회선이 고정되고, 데이터는 고정회선을 통해 전달됩니다.
  • TCP는 보낸 데이터가 순서대로 전달되며 손실이 발생하지 않습니다.
  • ServerSocket은 클라이언트의 연결을 수락하는 서버 쪽 클래스이고, Socket은 클라이언트에서 연결 요청할 때와 클라이언트와 서버 양쪽에서 데이터를 주고 받을때 사용되는 클래스 입니다.

  • 세그먼트(segment) : TCP 단위에서 전송되는 데이터의 단위입니다.
  • 패킷(packet : pack + bucket) : IP단위에서 호칭되는 데이터의 단위입니다.

  • TCP서버 프로그램을 개발하려면 우선 ServerSocket 객체를 생성합니다.
ServerSocket serverSocket = new ServerSocket(50001);
  • 기본 생성자로 객체를 생성하고 Port바인딩을 위해 bind() 메소드를 호출해서 ServerSocket 객체를 생성합니다.
ServerSocket serverSocket = new SeverSocket();
serverSocket.bind(new InetSocketAddress(50001));
  • 여러개의 IP가 할당된 서버 컴퓨터에서 특정 IP에서만 서비스를 하려면 InetSocketAddress의 첫번째 매개값으로 해당 IP를 줍니다.
ServerSocket = serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("xxx.xxx.xxx.xxx", 500001));
  • Port가 이미 다른 프로그램에서 사용 중이라면 BindException이 발생합니다.
  • 따라서 다른 Port로 바인딩 하거나 Port를 사용중인 프로그램을 종료하고 다시 실행해야 합니다.
  • ServerSocket이 생성되면 연결 요청을 수락을 위해 accept() 메소드를 실행합니다.
  • accept()는 클라이언트가 연결 요청하기 전 까지 블로킹(실행 멈춘상태)하고, 클라이언트의 연결 요청이 들어오면 블로킹이 해제되고 통신용 Socket을 리턴합니다.
Socket socket = serverSocket.accept();
  • 리턴된 Socket을 통해 연결된 클라이언트의 IP 주소와 Port 번호를 얻으려면 getRemoteSocketAddress() 메소드를 호출해서 InetSocketAddress를 얻은 다음 getHostName()과 getPost()메소드를 호출 합니다.
InetSocketAddress isa = (InetSocketAddress) socket.getRemote.SocketAddress();
String clientIp = isa.getHostName();
String portNo = isa.getPort();
  • ServerSocket의 close() 메소드를 호출해서 Port 번호를 언바인딩 해야 서버가 종료됩니다.
serverSocket.close();

 


TCP 서버 생성하는 소스코드

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ServerExam {
	private static ServerSocket serverSocket = null;
	
	public static void main(String[] args) {
		
		System.out.println("----------------------------------------------");
		System.out.println("서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력 하세요.");
		System.out.println("----------------------------------------------");
		
		//서버 소켓을 시작.
		startServer();
		
		//키보드 입력
		Scanner sc = new Scanner(System.in);
		while(true) {
			String key = sc.nextLine();
			
			//입력 문자를 소문자로 변환후 q 인지 확인후 맞을때 while문 종료
			if(key.toLowerCase().equals("q")) {
				break;
			}
		}
		sc.close();
		
		//서버 소켓 닫기
		stopServer();
	}
	
	public static void startServer() {
		//작업 스레드 정의
		Thread thread = new Thread() {
			@Override
			public void run() {
				try {
					//ServerSocket 생성 및 Port 바인딩
					serverSocket = new ServerSocket(50001);
					System.out.println("[서버] 시작됨");
					
					while(true) {
						System.out.println("\n[서버] 연결 요청을 기다림\n");
						
						// 클라이언트가 접속시 서버와 연결 통로 하나 생성
						Socket socket = serverSocket.accept();
						
						// 연결된 클라이언트 정보 확인
						InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
						System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");
						
						//연결 끊기
						socket.close();
						System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음");
					}
				}catch (IOException e) {
					System.out.println("[서버] " + e.getMessage());
				}
			}
		};
		// 스레드 시작
		thread.start();
		
	}
	public static void stopServer() {
		try {
			//ServerSocket을 닫고 Port 언바인딩
			serverSocket.close();
			System.out.println("[서버] 종료됨");
		}catch (IOException e1) {
		}
	}
}
결과 :
----------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력 하세요.
----------------------------------------------
[서버] 시작됨

[서버] 연결 요청을 기다림

yes
q
[서버] 종료됨
[서버] socket closed

 


TCP 클라이언트

  • 클라이언트가 서버에 연결 요청을 하려면 Socket 객체를 생성할 때 생성자 매개값으로 서버 IP주소와 Port 번호를 제공합니다.
  • 로컬 컴퓨터에서 실행하는 서버로 연결 요청을 할 경우에는 IP주소 대신 localhost를 사용 가능합니다.
Socket socket = new Socket("IP", 500001);
  • 도메인 이름을 사용하려면 DNS에서 IP주소를 검색하는 생성자 매개값으로 InetSocketAddress를 제공합니다.
Socket socket = new Socket(new InetSocketAddress("domainName", 50001);
  • 기본 생성자로 Socket을 생성한 후 connect() 메소드로 연결 요청이 가능합니다.
socket = new Socket();
socket.connect(new InetSocketAddress("domainName", 500001));

 


 TCP 클라이언트 생성하는 소스코드

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientExam {

	public static void main(String[] args) {

		try {
			//Socket 생성과 동시에 localhost의 500001 Port로 연결 요청;
			Socket socket = new Socket("localhost", 50001);
			
			System.out.println("[클라이언트] 연결 성공");
			
			socket.close();
			System.out.println("[클라이언트] 연결 끊음");
			
		}catch(UnknownHostException e) {
		}catch(IOException e) {
	}
	}
}
결과 :
[클라이언트] 연결 성공
[클라이언트] 연결 끊음

 


입출력 스트림으로 데이터 주고받기

  • 클라이언트가 연결 요청(connect())을 하고 서버가 연결 수락(accept())했다면, 양쪽의 Socket객체로부터 각각 InputStream과 OutputStream을 얻을 수 있습니다.

  • 상대방에게 데이터를 보낼 때에는 보낼 데이터를 byte[] 배열로 생성하고, 이것을 매개값으로 해서 OutputStream의 write() 메소드를 호출합니다.
  • 문자열을 좀 더 간편하게 보내고 싶다면 보조 스트림인 DataOutputStream을 연결해서 사용합니다.
String data = " 보낼 데이터 ";
byte[] bytes = data.getBytes("UTF-8");
OutputStream os = socket.getOutputStream();
os.write(bytes);
os.flush();
// DataOutputStream을 사용하여 문자열을 간편하게 보내기

String data = "보낼 데이터";
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(data);
dos.flush();
  • 데이터를 받기 위해서는 받은 데이터를 저장할 byte[] 배열을 하나 생성하고, 이것을 매개값으로 해서 InputStream의 read() 메소드를 호출 해야 합니다.
  • read() 메소드는 읽은 데이터를 byte[] 배열에 저장하고 읽은 바이트 수를 리턴합니다.
  • 문자열을 좀 더 간편하게 받고 싶다면 보조 스트림인 DataInputStream을 연결해서 사용
byte[] bytes = new byte[1024];
InputStream is = socket.getInputStream();
int num = is.read(bytes);
String data = new String(bytes, 0, num, "UTF-8");
DataInputStream dis = new DataInputStream(socket.getInputStream());
String data = dis.readUTF();

 


TCP 클라이언트가 보낸 메시지를 다시 돌려 보내는 에코 TCP 서버를 구현한 예제

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class EchoServer {
	private static ServerSocket serverSocket = null;
	
	public static void main(String[] args) {

		System.out.println("------------------------------------------");
		System.out.println("서버를 종료하려면 q를 입력하고 Enter 키를 입력 하세요.");
		System.out.println("------------------------------------------");
		
		//TCP 서버 시작
		startServer();
		
		//키보드 입력
		Scanner sc = new Scanner(System.in);
		while(true) {
			String key = sc.nextLine();
			if(key.toLowerCase().equals("q")) {
				break;
			}
		}
		sc.close();
		
		stopServer();
	}
	
	public static void startServer() {
		//작업 스레드 정의
		Thread thread = new Thread() {
			@Override
			public void run() {
				try {
				//ServerSocket 생성 및 Port 바인딩
				serverSocket = new ServerSocket(50001);
				System.out.println("[서버] 시작됨");
				
				while(true) {
					System.out.println("\n[서버] 연결 요청을 기다림\n");
					//연결수락
					Socket socket = serverSocket.accept();
					
					//연결된 클라이언트 정보 얻기
					InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
					System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");
					
//					InputStream is = socket.getInputStream();
//					byte[] bytes = new byte[1024];
//					int readByteCount = is.read(bytes);
//					String message = new String(bytes, 0, readByteCount, "UTF-8");
//					
//					OutputStream os = socket.getOutputStream();
//					bytes = message.getBytes("UTF-8");
//					os.write(bytes);
//					os.flush();
//					System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);
					
					DataInputStream dis = new DataInputStream(socket.getInputStream());
					String message = dis.readUTF();
					
					DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
					dos.flush();
					System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);
					
					//연결 끊기
					socket.close();
					System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음");
				}
				}catch (IOException e) {
					System.out.println("[서버] " + e.getMessage());
				}
			}
		};
		//스레드 시작
		thread.start();
	}
	
	public static void stopServer() {
		try {
			//ServerSocket을 닫고 port 언바인딩
			serverSocket.close();
			System.out.println("[서버] 종료됨");
		}catch(IOException e) {}
	}
}
결과 :
------------------------------------------
서버를 종료하려면 q를 입력하고 Enter 키를 입력 하세요.
------------------------------------------
[서버] 시작됨

[서버] 연결 요청을 기다림

 


TCP클라이언트 소스코드 구현

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class EchoClient {

	public static void main(String[] args) {

		try {
			
			//Socket 생성과 동시에 localhost의 50001 포트로 연결 요청;
			Socket socket = new Socket("172.20.10.18", 50001);
			
			System.out.println("[클라이언트] 연결 성공");
			
//			//데이터 보내기
//			String sendMessage = "나는 자바가 좋...ㅇ....";
//			OutputStream os =socket.getOutputStream();
//			byte[] bytes = sendMessage.getBytes("UTF-8");
//			os.write(bytes);
//			os.flush();
//			System.out.println("[클라이언트] 데이터 보냄: " + sendMessage);
//			
//			//데이터 받기
//			InputStream is = socket.getInputStream();
//			bytes = new byte[1024];
//			int readByteCount = is.read(bytes);
//			String receiveMessage = new String(bytes, 0, readByteCount, "UTF-8");
//			System.out.println("[클라이언트] 데이터 받음 : " + receiveMessage);
			
			String sendMessage = "행배야 오늘 날씨 직인다~!";
			DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
			dos.writeUTF(sendMessage);
			dos.flush();
			System.out.println("[클라이언트] 데이터 보냄 : " + sendMessage);
			
			//데이터 받기
			DataInputStream dis = new DataInputStream(socket.getInputStream());
			String reciveMessage = dis.readUTF();
			System.out.println("[클라이언트] 데이터 받음: " + reciveMessage);
			
			//연결 끊기
			socket.close();
			System.out.println("[클라이언트] 연결 끊음");
		}catch(Exception e) {
		}
	}
}
결과:
[클라이언트] 연결 성공
[클라이언트] 데이터 보냄 : 행배야 오늘 날씨 직인다~!
[클라이언트] 데이터 받음: 행배야 오늘 날씨 직인다~!
[클라이언트] 연결 끊음

 


UDP

  • 발신자가 일방적으로 수신자에게 데이터를 보내는 방식입니다.
  • TCP 처럼 연결 요청 및 수락 과정이 없기 때문에 TCP보다 데이터 전송 속도가 상대적으로 빠릅니다.
  • 데이터전달의 신뢰성보다 속도가 주용하다면 UDP를 사용하고, 데이터 전달의 신뢰성이 중요 하다면 TCP를 사용합니다.
  • DatagramSocket은 발신점과 수신점에 해당하고 DatagramPacket은 주고 받는 데이터에 해당합니다.

 


UDP 서버

  • DatagramSocket 객체를 생성 할 때에는 다음과 같이 바인딩할 Port번호를 생성자 매개값으로 제공합니다.

  • receive() 메소드는 데이터를 수신할 때 까지 블로킹되고, 데이터가 수신되면 매개값으로 주어진 DatagramPacket에 저장합니다.

  • DatagramPacket 생성자의 첫 번째 매개값은 수신된 데이터를 저장할 배열이고 두 번째 매개값은 수신할 수 있는 최대 바이트 수입니다.

  • getSocketAddress() 메소드를 호출하면 정보가 담긴 SocektAddress 객체를 얻을 수 있습니다.

  • SocketAddress 객체는 클라이언트로 보낼 DatagramPacket을 생성할 때 네번째 매개값으로 사용 합니다.

  • DatagramPacket을 클라이언트로 보낼 때는 DatagramSocket의 send()메소드를 이용합니다.

  • UDP 서버를 종료하고 싶을 경우에는 DatagramSocket의 close() 메소드를 호출합니다.


UDP 클라이언트가 구독하고 싶은 뉴스 10개를 전송하는 UDP 서버 구현예제

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.util.Scanner;

public class NewsServer {

	private static DatagramSocket datagramSocket = null;

		public static void main(String[] args) {
		System.out.println("-----------------------------------------");
		System.out.println("서버를 종료하려면 q를 입력하고 Enter키를 입력 하세요.");
		System.out.println("-----------------------------------------");

		//UDP 서버 시작
		startServer();
		
		Scanner sc = new Scanner(System.in);
		while(true) {
			String key = sc.nextLine();
			if(key.toLowerCase().equals("q")) {
				break;
			}
		}
		sc.close();
		
		//UDP 서버  종료
		stopServer();
	}
	public static void startServer() {
		// 작업 스레드 정의
		Thread thread = new Thread() {
			@Override
			public void run() {
				try {
					datagramSocket = new DatagramSocket(50001);
					System.out.println("[서버] 시작됨");
					
					while(true) {
						// 클라이언트에서 보내는 데이터를 받을 DatagramPacket을 생성
						DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
						//클라이언트로부터 데이터를 받으면 활성화가 됩니다.
						//receive : 대기상태 -> 데이터받음 -> 활성화
						datagramSocket.receive(receivePacket);
						//클라이언트가 보낸 데이터를 스트링 형태로 변환
						String newsKind = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
						
						//클라이언트의 IP와 port 얻기
						SocketAddress socketAddress = receivePacket.getSocketAddress();
						
						//10개의 뉴스를 클라이언트로 전송
						for(int i = 0; i<=10; i++) {
							String data = newsKind + ": 뉴스" + i;
							byte[] bytes = data.getBytes("UTF-8");
							DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
							datagramSocket.send(sendPacket);
						}
					}
				} catch (Exception e) {
					System.out.println("[서버] " + e.getMessage());
				}
			}
		};
		//스레드 시작
		thread.start();
	}
	
	public static void stopServer() {
		//DatagramSocket을 닫고 Port 언바인딩
		datagramSocket.close();
		System.out.println("[서버] 종료됨");
	}
}
결과:
-----------------------------------------
서버를 종료하려면 q를 입력하고 Enter키를 입력 하세요.
-----------------------------------------
[서버] 시작됨

 


UDP 클라이언트

  • 서버에 요청내용을 보내고 그결과를 받는 역할입니다.
  • UDP 클라이언트를 위한 DatagramSocket 객체는 기본 생성자로 생성하고, Port번호는 자동으로 부여합니다.

  • 생성된 DatagramPacket을 매개값으로 해서 DatagramSocket의 send() 메소드를 호출하면 UDP 서버로 DatagramPacket()이 전송됩니다.

  • DatagramSocket을 닫으려면 close() 메소드를 호출합니다.


 

NewsServer로 구독하고 싶은 뉴스 주제를 보내고 관련 뉴스 10개를 받는 UDP 클라이언트 구현

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class NewsClient {

	public static void main(String[] args) {

		try {
			//datagramsocket 생성
			DatagramSocket datagramSocket = new DatagramSocket();

			//구독하고 싶은 뉴스 주제 보내기
			String data = "정치";
			byte[] bytes = data.getBytes("UTF-8");
			DatagramPacket sendPacket = 
					new DatagramPacket(bytes, bytes.length, new InetSocketAddress("172.20.10.18", 50001));
			datagramSocket.send(sendPacket);
			
			while(true) {
				//뉴스 받기
				DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
				datagramSocket.receive(receivePacket);
				
				//문자열로 변환
				String news = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
				System.out.println(news);
				if(news.contains("뉴스10")) {
					break;
				}
			}
			datagramSocket.close();
		}catch(Exception e) {
		}
	}				
}
결과:
정치: 뉴스1
정치: 뉴스2
정치: 뉴스3
정치: 뉴스4
정치: 뉴스5
//해당 서버에서 5개만 출력되도록 만들어서 5개만 출력됩니다.

 

728x90

'JAVA > Java 기초' 카테고리의 다른 글

JSON 데이터형식.java  (0) 2023.02.01
서버의 동시 요청 처리.java  (0) 2023.02.01
기본 타입 스트림.java  (0) 2023.01.31
요소 커스텀 집계.java  (0) 2023.01.30
입출력 스트림-2.java  (0) 2023.01.30