네트워킹
- 네트워킹이란 두 대 이상의 컴퓨터를 케이블로 연결하여 네트워크를 구성하는 것을 의미합니다.
- 자바에서 제공하는 java.net패키지를 사용하면 이러한 네트워크 어플레케이션의 통신부분을 쉽게 작성할 수 있다
클라이언트. 서버
- 서버는 서비스를 제공하는 컴퓨터
- 클라이언트는 서비스를 사용하는 컴퓨터
- 네트워크를 구성할때 전용 서버를 두는 것을 서버기반 모델이라하고, 별도의 전용 서버 없이 각 클라이언트가 서버 역할을 동시에 수행하는 것을 p2p모델이라고 한다.
IP주소
- IP주소는 컴퓨터를 구변하는데 사용되는 고유한 값
- 4byte(32bit)의 정수로 구성되어 있으며, 'a.b.c.d'와 같은 형식
- 여기서 a.b.c.d는 부호없는 1바이트 값, 0~255사이의 정수
- IP주소는 네트워크 주소와 호스트 주소로 나눌 수 있으며, 각각 몇 비트인지는 네트워크를 어떻게 구성했는지에 따라 달라짐
- 콘솔에서 ipconfig를 실행하면 ip주소와 서브넷 마스크를 확인할 수 있음
- IP주소와 서브넷 마스크를 &로 연산을 수행하면 IP주소에서 네트워크 주소만을 뽑아낼 수 있음
InetAddress
- 자바에서는 IP주소를 다루기 위한 클래스로 InetAddress를 제공한다.
package ch16;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class NetworkEx1 {
public static void main(String[] args) {
InetAddress ip = null;
InetAddress[] ipArr = null;
try{
// 호스트 명을 통해 IP주소를 얻는다.
ip = InetAddress.getByName("www.naver.com");
// 호스트 이름을 반환한다.
System.out.println("getHostname() : " + ip.getHostName());
// 호스트의 IP주소를 반환한다.
System.out.println("getHostAddress() : " + ip.getHostAddress());
System.out.println("toString() : " + ip.toString());
// ip주소를 byte배열로 반환한다.
byte[] ipAddr = ip.getAddress();
System.out.println("getAddress() : " + Arrays.toString(ipAddr));
String result = "";
for(int i=0;i<ipAddr.length;i++){
result += (ipAddr[i] < 0) ? ipAddr[i] + 256 : ipAddr[i];
result += ".";
}
System.out.println("getAddress() + 256" + result);
System.out.println();
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
ip = InetAddress.getLocalHost();
System.out.println("getHostName() :" + ip.getHostName());
System.out.println("getHostAddress() : " + ip.getHostAddress());
System.out.println();
}catch (UnknownHostException e){
e.printStackTrace();
}
try{
ipArr = InetAddress.getAllByName("www.naver.com");
for(int i=0;i< ipArr.length;i++){
System.out.println("ipArr[" + i + "]:" + ipArr[i]);
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
URL
- URL은 인터넷에 존재하는 여러 서버들이 제공하는 자원에 접근할 수 있는 주소를 표현한 것
- 프로토콜://호스트명:포트번호/경로명/파일명?쿼리스트링#참조
- 프로토콜 : 자원에 접근하기 위해 서버와 통신하는데 사용하는 통신 규약(http)
- 호스트명 : 자원을 제공하는 서버의 이름
- 포트번호 : 통신에 사용되는 포트의 번호
- 경로명 : 접근하려는 자원이 저장된 서버상의 위치
- 파일명 : 접근하려는 자원의 이름
- 쿼리 : URL에서 '?'이후의 부분
- 참조 : URL에서 #이후의 부분
package ch16;
import java.net.MalformedURLException;
import java.net.URL;
public class NetworkEx2 {
public static void main(String[] args) throws Exception {
URL url = new URL("http://www.codechobo.com:80/post/free/34");
// 호스트명과 포트를 문자열로 반환한다.
System.out.println("url.getAuthority():" + url.getAuthority());
// URL의 content객체를 반환한다.
System.out.println("url.getContent():" + url.getContent());
// URL의 기본 포트를 반환함
System.out.println("url.getDefaultPort()" + url.getDefaultPort());
// 포트를 반환한다.
System.out.println("url.getPort() : " + url.getPort());
// 파일명을 반환한다.
System.out.println("url.getFile() : " + url.getFile());
// 호스트명을 반환한다.
System.out.println("url.getHost() : " + url.getHost());
// 경로명을 반환한다.
System.out.println("url.getPath() : " + url.getPath());
// 프로토콜을 반환한다.
System.out.println("url.getProtocol() : " + url.getProtocol());
// 쿼리를 반환한다.
System.out.println("url.getQuery() : " + url.getQuery());
// 참조를 반환한다.
System.out.println("url.getRef() : " + url.getRef());
// 사용자 정보를 반환한다.
System.out.println("url.getUserInfo() : " + url.getUserInfo());
// URL을 문자열로 변환하여 반환한다.
System.out.println("url.toExternalForm() : " + url.toExternalForm());
// URL을 URI로 변환하여 반환한다.
System.out.println("url.toURI() : " + url.toURI());
}
}
URLConnection
- 어플리케이션과 URL간의 통신연결을 나타내는클래스의 최상위 클래스
- URLConnection을 상속받은 클래스로 HttpURLConnection과 JarURLConnection이 있다.
public static void main(String[] args) {
URL url = null;
String address = "http://www.codechobo.com/post/free/31";
try{
url = new URL(address);
URLConnection conn = url.openConnection();
System.out.println("conn.toString():" + conn);
// UserInteraction의 허용여부 반환
System.out.println("getAllowUserInteraction() : " + conn.getAllowUserInteraction());
// 연결 종료시간을 천분의 일초로 반환
System.out.println("getConnectionTimeout(): " + conn.getConnectTimeout());
// content객체 반환
System.out.println("getContent() : " + conn.getContent());
// content의 인코딩을 반환한다.
System.out.println("getContentEncoding() : " + conn.getContentEncoding());
// content의 크기를 반환한다.
System.out.println("getContentLength() : " + conn.getContentLength());
// content의 type을 반환한다.
System.out.println("getConetentType() : " + conn.getContentType());
// 헤더의 date필드값을 반환한다.
System.out.println("getDate() : " + conn.getDate());
// UserInteration의 허용여부 반환한다.
System.out.println("getDefaultAllowUserInteration() : " + conn.getDefaultAllowUserInteraction());
// doInput필드값을 얻는다.
System.out.println("getDoInput (): " + conn.getDoInput());
// doOutput필드값을 얻는다.
System.out.println("getDoOutput () : " + conn.getDoOutput());
System.out.println("getExpiration () : " + conn.getExpiration());
System.out.println("getHeaderFields() : " + conn.getHeaderFields());
System.out.println("getIfModifiedSince() : " + conn.getIfModifiedSince());
System.out.println("getLastModified () : " + conn.getLastModified());
System.out.println("getReadTimeout() : " + conn.getReadTimeout());
System.out.println("getURL() : " + conn.getURL());
System.out.println("getUseCaches() : " + conn.getUseCaches());
} catch (Exception e) {
e.printStackTrace();
}
}
package ch16;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class NetworkEx3 {
public static void main(String[] args) {
URL url = null;
String address = "http://www.codechobo.com/post/free/31";
try{
url = new URL(address);
URLConnection conn = url.openConnection();
System.out.println("conn.toString():" + conn);
// UserInteraction의 허용여부 반환
System.out.println("getAllowUserInteraction() : " + conn.getAllowUserInteraction());
// 연결 종료시간을 천분의 일초로 반환
System.out.println("getConnectionTimeout(): " + conn.getConnectTimeout());
// content객체 반환
System.out.println("getContent() : " + conn.getContent());
// content의 인코딩을 반환한다.
System.out.println("getContentEncoding() : " + conn.getContentEncoding());
// content의 크기를 반환한다.
System.out.println("getContentLength() : " + conn.getContentLength());
// content의 type을 반환한다.
System.out.println("getConetentType() : " + conn.getContentType());
// 헤더의 date필드값을 반환한다.
System.out.println("getDate() : " + conn.getDate());
// UserInteration의 허용여부 반환한다.
System.out.println("getDefaultAllowUserInteration() : " + conn.getDefaultAllowUserInteraction());
// doInput필드값을 얻는다.
System.out.println("getDoInput (): " + conn.getDoInput());
// doOutput필드값을 얻는다.
System.out.println("getDoOutput () : " + conn.getDoOutput());
// 자원의 만료일자를 얻는다
System.out.println("getExpiration () : " + conn.getExpiration());
// 헤더의 n번째 필드를 얻는다.
System.out.println("getHeaderFields() : " + conn.getHeaderFields());
//ifModifiedSince필드의 값을 반환
System.out.println("getIfModifiedSince() : " + conn.getIfModifiedSince());
// 최종변경일 필드의 값을 반환한다.
System.out.println("getLastModified () : " + conn.getLastModified());
// 읽기 제한시간의 값을 반환한다.
System.out.println("getReadTimeout() : " + conn.getReadTimeout());
// URLConnection의 url을 반환한다.
System.out.println("getURL() : " + conn.getURL());
// 캐쉬의 사용여부를 반환한다.
System.out.println("getUseCaches() : " + conn.getUseCaches());
} catch (Exception e) {
e.printStackTrace();
}
}
}
package ch16;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
public class NetworkEx4 {
public static void main(String[] args) {
URL url = null;
BufferedReader input = null;
String address = "http://www.codechobo.com/post/free/31";
String line = "";
try{
url = new URL(address);
input = new BufferedReader(new InputStreamReader(url.openStream()));
while((line=input.readLine()) != null){
System.out.println(line);
}
input.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
-openStream()은 openConnection()을 호출하여 URLConnection을 얻은 다음 여기에 getInputStream()을 호출한 것이다.
소켓 프로그래밍
- 소켓 프로그래밍은 소켓을 이용한 통신 프로그래밍을 뜻함
- socket : 프로세스간 통신에 사용되는 양쪽 끝단
- TCP :
1. 연결기반
2. 연결 후 통신
3. 1:1 통신 방식
4. 데이터 전송순서를 보장하고, 데이터의 수신여부를 확인하는 등 신뢰성 있는 데이터 전송 보장
5. 관련 클래스로 Socket, ServerSocket이 있다.
6. 데이터의 경계를 구분하지 않는다(byte-stream)
- UDP :
1. 비연결기반
2. 연결없이 통신
3. 1:1, 1:n. n:n 통신방식
4. 데이터의 전송 순서가 바뀔 수 있고 데이터의 수신 여부를 확인하지 않기 때문에 신뢰성이 없음 대신 속도가 빠름
5. 데이터의 경계를 구분함(datagram)
TCP 소켓프로그래밍
- 클라이언트와 서버간의 일 대 일 통신
- 서버와 클라이언트 프로그램간의 통신과정은 다음과 같음
1. 서버 프로그램에서는 서버 소켓을 사용하여 서버 컴퓨터의 특정 포트에서 클라이언트의 연결 요청을 처리할 준비를 함
2. 클라이언트 프로그램은 접속할 서버의 IP주소와 포트 정보를 가지고 소켓을 생성해서 서버에 연결을 요청함
3. 서버 소켓은 클라이언트의 연결 요청을 받아 서버에 새로운 소켓을 생성하여 클라이언트의 소켓과 연결되도록 함
4. 클라이언트의 소켓과 새로 생성된 서버의 소켓은 서버 소켓과 관계없이 일대일통신을 한다.
- 서버 소켓은 소켓간의 연결만 처리하고 실제 데이터는 소켓들끼리 주고받는다.
- 소켓들의 데이터를 주고받는 연결통로는 입출력 스트림
- 자바에서는 TCP를 이용한 소켓프로그래밍을 위해 Socket과 ServerSocket클래스를 제공함
- Socket : 프로세스간 통신 담당하며, InputStream과 OuputStream가지고 있음
- ServerSocket : 포트와 연결되어 외부의 연결요청을 기다리다 연결요청이 들어오면, Socket을 생성하여 소켓과 소켓간의 통신이 가능하도록 한다. 한 포트에 하나의 ServerSocket만 연결 가능
-다음은 TCP/IP를 이용하는 간단한 클라이언트 / 서버 프로그램이다.
package ch16;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TcpIpServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(7777);
System.out.println(getTime() + "서버가 준비되었습니다.");
while (true) {
System.out.println(getTime() + "연결 요청을 기다립니다.");
// 서버 소켓이 클라쪽의 연결 요청이 올때까지 실행을 멈추고 계속 기다림
// 클라이언트의 연결 요청이 오면 클라 소켓과 통신할 새로운 소켓을 생성한다.
Socket socket = serverSocket.accept();
System.out.println(getTime() + socket.getInetAddress() + "로부터 연결요청이 들어왔습니다.");
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
dos.writeUTF("[Notice] Text Message1 from Server");
System.out.println(getTime() + "데이터를 전송하였습니다.");
dos.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
static String getTime(){
SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
return f.format(new Date());
}
}
package ch16;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpIPClient {
public static void main(String[] args) {
try{
String serverIp = "127.0.0.1";
System.out.println("서버에 연결중입니다.");
Socket socket = new Socket(serverIp, 7777);
InputStream in =socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
System.out.println("서버로부터 받은 메세지 : " + dis.readUTF() );
System.out.println("연결을 종료합니다.");
dis.close();
socket.close();
System.out.println("연결이 종료되었습니다.");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
실행 프로세스는 다음과 같다.
- 1. 서버 프로그램을 실행한다.
- 2. 서버 소켓을 생성한다.
- 3. 서버 소켓이 클라이언트 프로그램의 연결 요청을 처리할 수 있도록 대기상태로 만든다. 클라이언트 프로그램의 연결 요청이 오면 새로운 소켓을 생성해서 클라이언트 프로그램의 소켓과 연결한다.
- 4. 클라이언트 프로그램에서 소켓을 생성하여 서버 소켓에 연결을 요청한다.
- 5. 서버 프로그램은 클라이언트 프로그램의 요청을 받아 새로운 소켓을 생성하여 클라이언트 소켓과 연결한다.
- 6. 서버 소켓은 클라이언트 프로그램의 연결 요청을 받아 새로운 소켓을 생성하여 클라이언트 프로그램의 소켓과 연결한다.
- getPort(): 상대편 소켓이 사용하는 포트 반환
- getLocalPort(): 소켓 자신이 사용하는 포트 반환
- setSoTimeout(int timeout) : 서버 소켓의 대기시간 지정 가능. 지정한 시간이 지나면 accept()에서 SocketTimeoutException을 발생시킨다.