본문 바로가기

Master_branch/study_branch

Java Socket Client (TCP/IP) 소켓 프로그래밍

이번 포스팅에서는 Java Socket 프로그래밍에 대해서 포스팅 하려고 합니다 :)

 

TCP/IP 프로토콜을 사용하여 서버와 통신하는 클라이언트 프로그램을 작성하는 방법입니다.

 


클라이언트 소켓  API

 

Socket 클래스는 소켓 클라이언트를 나타냅니다. 

 

이 클래스를 사용해서 서버와의 연결 / 서버로 데이터 전송 / 서버에서 데이터 리딩 을 할 수 있습니다.

 

일반적인 통신의 단계는

 

Step 1. 클라이언트가 호스트 이름 / IP 주소 및 포트 번호로 지정된 서버에 대한 연결 시작
Step 2. OutputStream을 사용하여 서버에 데이터 전송
Step 3. InputStream을 사용하여 서버에서 데이터를 읽음
Step 4. 연결을 종료

 

Step 2와 Step 3은 통신의 성격에 따라 여러 번 반복 될 수 있습니다

 

Socket 클래스를 사용하여 Step1 ~ Step 4 까지의 단계를 살펴보도록 하겠습니다.

 

 

Step 1. 서버에 대한 연결 시작

 

 

Initiate Connection to a Server

a - Socket(InetAddress address, int port)

b - Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

c - Socket(String host, int port)

 

서버에 연결하려면 위의 생성자 중 하나를 사용하여 새 Socket 객체를 만듭니다.

 

a와 c 두 생성자를 사용하면, 시스템은 클라이언트 컴퓨터에 사용 가능한 포트 번호와 로컬 주소를 자동으로 할당합니다.

b 생성자를 사용하면 필요에 따라 클라이언트의 주소와 포트 번호를 명시 할 수 있습니다.

 

위의 세 소켓 생성자는 소켓의 작성 중에 입출력 에러가 발생 할 경우가 있는데, 이 때를 대비해서 Exception 처리를 해 주어야 합니다. (IOException - UnknownHostException)

 

다음 코드는 naver.com에 포트 8000번으로 연결하려는 클라이언트 소켓을 만드는 java 코드입니다.

// import java.net.*;
// import java.io.*;

Socket socket = new Socket("naver.com", 8000);

 

 

Step 2. 서버에 데이터 보내기

 

서버에 데이터를 보내려면 먼저 소켓에서 OutputStream 객체를 가져와야 합니다.

OutputStream output = socket.getOutputStream();

 

객체를 가져 온 후에, OuputStream의 wirte() 메서드를 사용하여 보낼 바이트 배열을 쓸 수 있습니다.

String realStr = "This is woolbro dev Note";
byte[] data = realStr.getBytes(); //getBytes() 메서드를 사용 해 문자열을 Byte로 바꿔준다
output.write(data);

 

 PrintWirte에 OutputStream을 래핑하여 다음과 같이 데이터를 텍스트 형식으로 보낼 수 있습니다.

PrintWriter writer = new PrintWriter(output, true); //true 인수는 메소드 호출 후에 데이터 자동비우기 설정입니다.
writer.println("This is a Message From Woolbro devNote"); 

 

 

 Step 3. 서버에서 데이터 읽기

 

마찬가지로 서버에서 데이터를 읽으려면 클라이언트 소켓에서 InputStream 객체를 가져와야 합니다.

InputStream input = socket.getInputStream();

 

그런다음 InputStream에서 read() 메서드를 사용하여 데이터를 읽습니다.

input.read(data); // byte[] data=....

 

InputStreamReader 와 BufferedReader 또한 사용 할 수 있습니다.

//InputStreamReader
InputStreamReader reader = new InputStreamReader(input);
int character = reader.read();


//BufferedReader
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line = reader.readLine();

 

 

Step 4. 연결 종료

소켓에서 close() 메서드를 호출하여 클라이언트와 서버 간의 연결을 종료합니다.

socket.close();

 


Java Socket Client Example #1

package com.woolbro.socketprg;

import java.net.*;
import java.io.*;
 
public class WhoisClient {
 
    public static void main(String[] args) {
    	if (args.length < 1) {
    		System.out.println("Argumnets is null....");
    		return;
    	}
    	 
        String domainName = args[0];
 
        String hostname = "whois.internic.net";
        int port = 43;
 
        try (Socket socket = new Socket(hostname, port)) {
 
            OutputStream output = socket.getOutputStream();
            PrintWriter writer = new PrintWriter(output, true);
            writer.println(domainName);
 
            InputStream input = socket.getInputStream();
 
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
 
            String line;
 
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (UnknownHostException ex) {
 
            System.out.println("Server not found: " + ex.getMessage());
 
        } catch (IOException ex) {
 
            System.out.println("I/O error: " + ex.getMessage());
        }
    }
}

Whois 클라이언트는 특정 도메인 이름에 대한 정보를 쿼리 할 수 있는 인터넷 서비스입니다.

whois.internic.net 도메인의 43 포트(Whois 프로토콜 용 포트 43)에서 서비스를 제공 받을 수 있습니다.

 

작성한 예제 코드는 args가 1개 필요합니다. 수정하셔서 args를 메인 메서드 내에 넣거나 이클립스의 Run Configuration에서 args인자 설정을 해주시면 됩니다. 혹은 Commandline 을 사용하여서 아래와 같이 실행 해 주셔도 됩니다.

java WhoisClient "인수" 

 

즉 java WhoisClient google.com 이면, google.com의 정보를 가져오는 것 입니다.

 

저는 tisory.com 을 검색했습니다.

   Domain Name: TISTORY.COM
   Registry Domain ID: 219936332_DOMAIN_COM-VRSN
   Registrar WHOIS Server: whois.ibi.net
   Registrar URL: http://www.ibi.net
   Updated Date: 2018-09-28T04:44:11Z
   Creation Date: 2005-10-01T16:49:05Z
   Registry Expiry Date: 2019-10-01T16:49:05Z
   Registrar: Netpia.com, Inc.
   Registrar IANA ID: 130
   Registrar Abuse Contact Email:
   Registrar Abuse Contact Phone:
   Domain Status: ok https://icann.org/epp#ok
   Name Server: NS1.DAUM.NET
   Name Server: NS2.DAUM.NET
   DNSSEC: unsigned
   URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
>>> Last update of whois database: 2019-06-25T17:28:06Z <<<

 

이렇게 나오네요...

 

 

Java Socket Client Example #2

 

다음은 SMTP 서버와 통신하는 예 입니다. HELO, QUIT 과 같은 간단한 SMTP 명령을 보내서 통신하는 예 입니다.

 

package com.woolbro.socketprg;
import java.net.*;
import java.io.*;
 
public class SmtpClient {
 
    public static void main(String[] args) {
 
        String hostname = "smtp.gmail.com";
        int port = 25;
 
        try (Socket socket = new Socket(hostname, port)) {
 
            InputStream input = socket.getInputStream();
 
            OutputStream output = socket.getOutputStream();
            PrintWriter writer = new PrintWriter(output, true);
 
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
 
            String line = reader.readLine();
            System.out.println(line);
 
            writer.println("helo " + hostname);
 
            line = reader.readLine();
            System.out.println(line);
 
            writer.println("quit");
            line = reader.readLine();
            System.out.println(line);
 
        } catch (UnknownHostException ex) {
 
            System.out.println("Server not found: " + ex.getMessage());
 
        } catch (IOException ex) {
 
            System.out.println("I/O error: " + ex.getMessage());
        }
    }
}

위의 코드를 실행하면 아래와같이 결과가 나와요 :)