본문 바로가기

JAVA/척척학사 스터디

[JAVA] 네트워크 프로그래밍

서버

여러 명의 사용자들에게 서비스를 제공하는 컴퓨터

클라이언트

서비스를 요청해서 사용하는 컴퓨터

IP 주소(IPv4)

네트워크에 존재하는 컴퓨터를 유일하게 식별하는 숫자

호스트 이름, DNS, URL

  • DNS(Domain Name System): 숫자 대신 기호를 사용하는 주소
  • DNS 서버: 기호 주소를 숫자 주소로 변환해주는 서버
  • URL(Uniform Resource Locator): 인터넷 상의 자원을 나타내는 약속

nslookup 명령어

nslookup naver.com

URL(Uniform Resource Locator)

인터넷 상의 파일이나 데이터베이스같은 자원에 대한 주소를 지정하는 방법

Ex) 호스트 이름을 받아서 IP 주소를 반환하는 프로그램을 작성해보자

public class host2ip 
{
  public static void main ( String[] args ) throws IOException   {
    String hostname = "www.naver.com";

    try     {
      InetAddress address = InetAddress.getByName(hostname);
      System.out.println("IP 주소: " + address.getHostAddress());
    }
    catch ( UnknownHostException e )  {
      System.out.println(hostname + "의 IP 주소를 찾을 수 없습니다. " );
    }
  }
}
더보기

IP 주소: 125.209.222.142

InetAddress.getByName()을 호출하여 호스트 이름을 전달하면, IP 주소를 저장하고 있는 객체가 반환됨

프로토콜(Protocol)

컴퓨터 간에 상호통신을 할 때 데이터를 원활하고 신뢰성 있게 주고 받기 위해 필요한 약속을 규정

전송 계층(Transport Layer) 기본 프로토콜 - TCP, UDP

TCP(Transmission Control Protocol) 통신

  • 먼저 서로 간에 연결을 설정한 후에 데이터를 보내고 받는 방식
  • 연결끝점(end point)이 바로 소켓

ServerSocket과 Socket 클래스

1. ServerSocket 객체 생성

  • ServerSocket server = new ServerSocket(portNumber, queueLength);

2. accept() 메소드 호출

  • 서버는 클라이언트가 연결을 시도하기를 기다린다.
  • 연결이 되면 새로운 Socket 객체를 생성한다.
  • Socket clientSocket = server.accept();

3. 소켓으로부터 스트림 객체를 얻는다.

  • InputStream input = clientSocket.getInputStream();
  • OutputStream output = clientSocket.getOutputStream();

Ex) 현재 시각을 알려주는 서버에 연결하기

public class SocketTest {
	public static void main(String[] args) throws IOException {
		try (Socket s = new Socket("time-c.nist.gov", 13)) {  //(사이트 주소, 포트번호)
			InputStream inStream = s.getInputStream();    //소켓으로부터 입력스트림 얻기
			Scanner in = new Scanner(inStream);  //in은 inStream 스트림을 읽게 된다

			while (in.hasNextLine()) {
				String line = in.nextLine();
				System.out.println(line);
			}
		}
	}
}
더보기

59453 21-08-27 06:34:46 50 0 0  65.7 UTC(NIST) *

인터넷에 보면 정확한 현재 시각을 알려주는 서버들이 존재한다(원자 시계로 측정된 시각이다). 여기서는 미국 시각을 알려주는 서버(NIST 서버)에 소켓을 이용하여 접속해 보자.
소켓은 Socket 클래스에 의하여 제공된다. Socket 클래스 생성자의 첫 번째 인수는 사이트 주소이고 두 번째 인수가 바로 포트 번호이다. NIST 서버를 지정하는 소켓을 생성하면 바로 서버와 연결된다.
소켓으로부터 입력 스트림을 얻어서 스트림에 읽으면 현재 시각을 알 수 있다.

UDP(User Datagram Protoocol) 통신

  • 데이터를 몇 개의 고정 길이의 패킷(데이터그램)으로 분할하여 전송

  • DatagramSocket 클래스
    • DatagramSocket()은 UDP 프로토콜을 사용하는 소켓을 생성
  • DatagramPacket 클래스
    • DatagramPacket()은 UDP 패킷을 생성

Ex) UDP 통신을 이용하여서 간단한 채팅을 할 수 있는 메신저를 작성하여 보자.

public class MessengerA {
       protected JTextField textField;
       protected JTextArea textArea;
       DatagramSocket socket;
       DatagramPacket packet;
       InetAddress address = null;
       final int myPort = 5000;		// 수신용 포트 번호
       final int otherPort = 6000;	// 송신용 포트 번호
 
       public MessengerA() throws IOException {
             MyFrame f=new MyFrame();
             address = InetAddress.getByName("127.0.0.1");
             socket = new DatagramSocket(myPort); 
       }
        // 패킷을 받아서 텍스트 영역에 표시한다. 
       public void process() {
             while (true) {
                    try {
                           byte[] buf = new byte[256];
                           packet = new DatagramPacket(buf, buf.length);
                           socket.receive(packet); // 패킷을 받는다. 
                           // 받은 패킷을 텍스트 영역에 표시한다. 
                           textArea.append("RECIEVED: " + new String(buf) + "\n");
                    } 
                    catch (IOException ioException) {
                           ioException.printStackTrace();
                    } 
             } 
       }
        // 내부 클래스 정의 
       class MyFrame extends JFrame implements ActionListener {
 
             public MyFrame() {
                    super("MessengerA");
                    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
                    textField = new JTextField(30);
                    textField.addActionListener(this);
 
                    textArea = new JTextArea(10, 30);
                    textArea.setEditable(false);
 
                    add(textField, BorderLayout.PAGE_END);
                    add(textArea, BorderLayout.CENTER);
                    pack();
                    setVisible(true);
             }
              public void actionPerformed(ActionEvent evt) {
                    String s = textField.getText();
                    byte[] buffer = s.getBytes();
                    DatagramPacket packet;

                    // 패킷을 생성한다.  
                    packet = new DatagramPacket(buffer, buffer.length, address,
                                 otherPort);
                    try {
                           socket.send(packet);	// 패킷을 보낸다. 
                    } catch (IOException e) {
                           e.printStackTrace();
                    }
                    textArea.append("SENT: " + s + "\n");
                    textField.selectAll();
                    textArea.setCaretPosition(textArea.getDocument().getLength());
             }
       }
 
       public static void main(String[] args) throws IOException {
             MessengerA m = new MessengerA();
             m.process();
       }
}
// 다음의 몇 개의 문장만 제외하고 MessengerA와 동일
.... 
public class MessengerB {
    ...
    final int myPort = 6000;
    final int otherPort = 5000;
 
    public MessengerB() throws IOException {
       ...
    }
    public static void main(String[] args) throws IOException {
        MessengerB m = new MessengerB();
        m.process();
    }
}

UDP 통신을 이용한 채팅 메신저