네트워킹
1. 학습 목표
- 네트워킹의 기본적 개념에 대해 설명할 수 있다.
- 자바에서의 URL 관련 클래스에 대해 설명할 수 있다.
- TCP 소켓을 이용한 서버/클라이언트 통신의 기본 구조에 대해 이해하고 응용 프로그램을 개발할 수 있다.
- UDP 소켓을 이용한 서버/클라이언트 통신의 기본구조에 대해 이해하고 응용프로그램을 개발할 수 있다.
2. 학습 내용
네트워킹
네트워킹의 개요
End System 들을 연결하는 하나의 System을 의미한
End System은 호스트로서 PC Workstaion printer 등
네트워크간 연결 시 경로를 제어하는 라우터가 사용됨
자바는 네트워크로 연결된 컴퓨터의 정보, 웹문서 정보를 탐색할 수 있음
컴퓨터간의 데이터 통신을 지원하는 java.net 패키지를 제공함
클라이언트/서버모델
정보의 흐름을 기준으로 정보를 제공하는 쪽이 서버, 받는 쪽이 클라이언트
서버와 클라이언트는 프로그램(machine이 아님)
서버는 클라이언트의 연결 요청을 대기
클라이언트는 서버에 요청을 하고 응답을 기다리는 컴퓨터를 의미
TCP/IP, 소켓, 포트
- TCP/IP 프로토콜 개념
- 네트워크를 사용하여 컴퓨터들간의 통신을 위한 규약을 프로토콜이라고 함
- 프로토콜을 계층적으로 정의되어 있으며, 인터넷에서 사용하는 TCP/IP(Internet Protocol) 프로토콜은 4개의 계층으로 구성되어 있음
- 자바에서 네트워크 관련 클래스를 이용해서 프로그래밍을 작성하는 것은 응용계층에서의 사용을 의미함

- TCP와 UDP
- 전달 켸층의 프로토콜에는 TCP와 UDP가 있음
TCP(Transmission Control protocol)
연결형
컴퓨터 상에서 가상의 경로(Router)를 설정하고 통신하는 방식
UDP(User Datagram Protocol)
비연결형
가상의 경로를 설정하지 않고, 목적지 주소를 갖는 데이터(패킷)를 다수의 경로로 보내는 방식
구분 | TCP | UDP |
신뢰성 | 높음 | 낮음 |
연결성 | 연결 지향적임 가상의 통신경로 설정 | 연결 비지향적임 통신경로 설정 없음 |
재전송 요구 | 오류/패킷손실 재정송 요구 있음 | 재전송 요구 없음 |
전송 속도 | 상대적으로 낮음 | 상대적으로 높음 |
응용 분야 | 신뢰성이 높은 분야 ftp | 실시간 전송 음성, 동영상 스트리밍 |
- 소켓(socket)
- 전기선의 소켓과 유사함
- 컴퓨터가 연결된 통신의 끝점을 의미한
- 상호 연결된 응용 프로그램들 사이의 정보 교환을 제공하고 있는 소프트웨어 매체임
- 자바 프로그램에서 TCP로 통신할 때는 TCP 소켓을 생성하고, UDP로 통신할 떄는 UDP 소켓을 생성해야 함
- 전기선의 소켓과 유사함
- 포트(port)
- 통신선을 통해 수신되는 데이터가 컴퓨터 내의 여러 통신 프로그램 중에서 하나의 프로그램에 전달되도록 하기 위한 번호임
- 인터넷을 통하여 전달되는 정보들은 목적지 컴퓨터의 주소(32비트)와 16비트의 포트번호로 구성됨
자바에서의 URL(Uniform Resource Locator) 관련 클래스
네트워크 상에서 자원이 어디 있는지를 알려주기 위한 규약
컴퓨터 네트워크와 검색 메커니즘에서의 위치를 지정하는 웹 리소스에 대한 참조를 말함
간단하게 말하면 웹 페이지를 찾기 위한 주소를 말함
흔히 웹 사이트 주소로 알고 있지만, URL은 웹 사이트 주소뿐만 아니라 컴퓨터 네트워크상의 자원을 모두 나타낼 수 있음
URL 클래스
Web에서 사용하는 URL에 관한 정보를 처리함
URL 클래스의 주요 메소드
메소드 | 설명 |
String getFile() | URL의 파일 이름을 반환 |
String getHost() | URL의 호스트 이름을 반환 |
String getPort() | URL의 프로토콜 이름을 반환 |
String getProtocol | URL의 프로토콜 이름을 반환 |
String toExternalForm() | 전체 URL의 문자열 객체를 반환 |
URLConnection openConnection() | 지정된 URL과 연결 후 URLConnection 객체를 반환 |
InputStream openStream() throws IOException | 지정된 URL로부터 정보를 읽어들이기 위한 객체를 반 |
- 참고 : 네트워크 관련 응용프로그램에서는 main 메소드에 예외처리를 다음과 같이 기술함
- throws IOExeption 표시가 있으면 예외 처리를 수행하라는 뜻을 말함
- throws는 예외가 발생하면 해당 메소드 내에서 처리하지 않고, 자신을 호출하는 메소드에서 처리하도록 함
- 오브젝트 생성이나 메소드는 throws IOException {…} 내에서 사용함
- 이 경우 main 메소드는 다음과 같이 사용함
public static void main(String[] args) throws IOException {
.
.
.
InputStream ist = URL.openStream();
.
.
.
}
- 메소드 내에서 예외를 처리하기 위해서는 try{} catch(IOException e){} 블록을 지정함.
- 이 경우 main 메소드를 다음과 같이 사용함
public void static main(String[] args) {
try{
.
.
InputStream ist = URL.openStream();
.
.
} catch(IOException e){
.
.
}
}
URLConnection 클래스
원격지 자원의 속성을 알아내기 위해 사용
원격 컴퓨터와 연결된 상태에서 원격지 자원의 속성을 탐색
URLConnection 클래스의 주요 메소드
메소드 | 설명 |
int getContentLength() | 해당 문서의 길이를 바이트 크기로 반환 |
String getContentType() | 해당 문서의 형식을 반환 |
long getDate() | 해당 문서의 생성 날짜를 반환 |
long getExpiration() | 해당 문서의 소멸 날짜를 반환 |
long getLastModified() | 해당 문서의 마지막 수정 날짜를 반환 |
InputStream getInputStream() throws IOException | 원격지로부터 정보를 읽어들이기 위한 InputStream 객체를 생성하여 반 |
원격지 자원의 속성 정보를 가져오는 순서
- URL 클래스를 이용하여 접속하려는 컴퓨터의 정보를 갖는 URL 오브젝트를 생성함
- URL 클래스의 OpenConnection() 메소드를 실행해서 URLConnection 오브젝트를 생성함
- URLConnection 오브젝트를 이용해서 속성을 가져옴
- URLConnection 클래스의 getInputStream() 메소드 또는 URL 클래스의 openStream() 메소드를 사용해서 원격지로부터 정보를 읽기 위한 InputStream 오브젝트를 생성함
- InputStream 오브젝트를 이용해서 원격지의 정보를 읽어옴
예
package ch14;
import java.io.*;
import java.net.*;
import java.util.*;
public class URLConnectionTest {
public static void main(String[] args) throws Exception {
URL w3c = new URL("https://www.w3.org/");
URLConnection w3cCon = w3c.openConnection();
System.out.println("문서의 타입 : " + w3cCon.getContentType());
System.out.println("최종 수정일자 : " + new Date(w3cCon.getLastModified()));
System.out.println("문서 내용 : ");
InputStream input = w3cCon.getInputStream();
int i = 500; // 최대 500문자까지만 읽음
int c;
while (((c = input.read()) != -1) && (--i > 0)) {
System.out.print((char) c);
}
input.close();
}
}

해당 문서의 타입과 최종 수정일자, 그리고 문서의 내용이 출력되는 모습이다.
TCP 소켓을 이용한 서버/클라이언트 통신
자바는 서버 클라이언트 응용 프로그램을 위한 ServerSocket 클래스와 Socket 클래스를 제공함
TCP는 연결 지향성 통신방법이므로 전송 전에 연결이 성립되어야 함
클라이언트는 소켓을 생성하여 서버쪽에 연결 요청을 하고, 서버는 accept() 메소드로 연결 요청을 수락함
서버가 응답하지 못하면 접속거부 에러가 발생
서버가 먼저 실행되어 클라이언트의 접속 요청을 대기하고 클라이언트의 접속 요청이 발생하면 서버는 그 요청을 처리하고 데이터를 클라이언트에 전송함

ServerSocket 클래스의 주요 메소드
메소드 | 설명 |
ServerSocket(int port) throws IOException | 생성자, port는 포트번호 |
Soket accept() throws IOException | 클라이언트의 요청을 받아들인 다음, Soket 클래스 객체를 반환 |
void close() throws IOException | 서버 소켓을 닫 |
Socket 클래스의 주요 메소드
메소드 | 설명 |
Soket(String hostName, int port) throws UnknownHostException, IOException | 생성자, hostName은 연결하고자 하는 컴퓨터의 주소, port는 포트번호 |
OutputStream getOutputStream() throws IOException | 현재의 소켓과 관련된 OutputStream 객체를 반환 |
void close() throws IOException | 소켓을 닫음 |
InetAddress getInetAddress() | 현재 소켓에 연결된 컴퓨터의 주소를 반환 |
InetAddress getLocalAddress() | 현재 소켓을 사용하고 있는 컴퓨터의 주소를 반환 |
int getPort() | 현재 소켓에 연결된 컴퓨터의 포트 번호를 반환 |
int getLocalPort() | 현재 소켓이 사용하고 있는 포트 번호를 반환 |
InputStream getInputStream() throws IOException | 현재 소켓과 관련된 InputStream 객체를 반 |
서버/클라이언트간 통신의 순서(TCP)
- 서버

- 클라이언트

예제
서버에서 클라이언트로 데이터를 전송하고 클라이언트는 수신한 데이터를 출력
명령 프롬프트참에서 서버 프로그램을 실행시킨 후, 다른 명령 프롬프트창에서 클라이언트 프로그램을 실행시
// TCPServer
// 사용예 : java TCPServer 포트번호
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws Exception{
int port = Integer.parseInt(args[0]);
ServerSocket ssocket = new ServerSocket(port); // 서버소켓 생성
System.out.println("server is running...");
while(true){
Socket csocket = ssocket.accept(); // 연결수락, 클라이언트 소켓 생성
OutputStream ostream = csocket.getOutputStream(); // 소켓 출력 스트림 생성
DataOutputStream dostream = new DataOutputStream(ostream); // 스트림 변환
for (int imsg = 1 ; imsg <= 5 ; imsg++) // 숫자 1~5를 5회에 걸쳐 송신
dostream.writeInt(imsg);
csocket.close();
}
}
}
// TCPClient
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws Exception{
String server = args[0];
int port = Integer.parseInt(args[1]);
Socket csocket = new Socket(server, port); // 클리이언트 소켓 생성(서버에 연결요청)
InputStream istream = csocket.getInputStream(); // 소켓입력 스트림 생성
DataInputStream distream = new DataInputStream(istream);
for (int i = 1; i <= 5; i++) {
int imsg = distream.readInt();
System.out.println("data to server : "+imsg);
}
csocket.close();
}
}
실행 결과


서버가 정상적으로 돌아가고 데이터를 요청해 결과를 받아오는 모습
UDP 소켓을 이용한 서버/클라이언트 통신
통신을 위해 데이터그램 소켓을 사용하지만 서버에 연결요청을 하지 않고 단순히 데이터 송신을 위한 소켓
UDP에서는 패킷에 데이터를 받을 못적지 주소와 포트번호를 기록한 후, 소켓을 통해서 전송함
자바는 UDP를 지원하는 DatagramSocket, DatagramPacket 클래스를 제공함
DatagramPacket 클래스는 응용 프로그램들이 주고받을 데이터와 관련있음
실제 데이터의 전송을 DatagramSocket 클래스에서 이루어짐
DatagramPacket 주요 메소드
DatagramPacket(byte[] buffer, int size) | 수신용 프로그램의 생성자, buffer는 수신하는 데이터를 저장할 바이트 배열, size는 배열의 크기 |
DatagramPacket(byte[] buffer, int size, InetAddress ia, int port) | 송신용 프로그램의 생성자, ia는 목적지 주소, port는 포트번호 |
InetAddress getAddress() | 수신 응용 프로그램에서 사용하며, 정보를 보낸 컴퓨터의 주소를 반환 |
byte[] getData() | 패킷으로부터 데이터를 읽어서 바이트 배열로 반환 |
int getLength() | 패킷의 바이트 수를 반환 |
int getPort() | 포트 번호를 반환 |
void setAddress(InetAddress ia) | Ia를 주소로 설정 |
void setData(byte buffer[]) | buffer의 내용을 패킷의 데이터로 설정 |
void setLength(int size) | 패킷의 크기를 size로 설정 |
void setPort(int port) | 포트 번호를 port값으로 설정 |
DatagramSocket 주요 메소드
DatagramSocket() throws SocketException | 생성자, 현재 가능한 포트중에서 하나를 선택 |
DatagramSocket(int port) throws SocketException | 생성자, port 번호 |
void receive(DatagramPacket dgram) throws IOException | 현재의 소켓으로부터 정보를 읽어 dgram 패킷에 저장 |
void send(DatagramPacket dgram) throws IOException | 현재의 소켓을 통하여 Dgram 패킷을 전송 |
void xlose() throws IOException | 소켓을 닫음 |
서버/클라이언트간 일방향 통신(UDP)
- 서버

- 클라이언트

예제
서버에서 클라이언트로 데이터를 전송하고 클라이언트는 수신한 데이터를 출력
명령 프롬프트참에서 클라이언트 프로그램을 실행시킨 후, 다른 명령 프롬프트창에서 서버 프로그램을 실행
//server
package ch14;
import javax.xml.crypto.Data;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPServer {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
InetAddress ia = InetAddress.getByName(args[0]);
int port = Integer.parseInt(args[1]);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input sending message(bye = quit");
String buf;
do {
buf = in.readLine(); // 키보드로부터 한줄 입력
byte buffer[] = buf.getBytes(); // 바이트 배열로 변환
DatagramPacket dp = new DatagramPacket(buffer, buffer.length, ia, port); // 패킷화
ds.send(dp);
} while (!buf.equals("bye"));
ds.close();
}
}
// client
package ch14;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPClient {
public static void main(String[] args) throws Exception{
int port = Integer.parseInt(args[0]);
DatagramSocket ds = new DatagramSocket(port);
String q;
do {
byte buffer[] = new byte[60];
// 패킷 오브젝트 생성
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp); // 패킷 수신
String msg = new String(dp.getData()); // 바이트 배열을 문자열로 변환
System.out.println("수신 메시지 : " + msg );
q = msg.substring(0, 3);
} while (!q.equals("bye"));
ds.close();
}
}


서버/클라이언트간 양방향 통신(UDP)
UDP를 이용한 에코 서버/클라이언트 통신 예제
클라이언트에서 서버로 데이터를 전송하고 서버는 전송받은 데이터를 그래로 클라이언트로 전송함
명령창에서 클라이언트 프로그램을 실행시킨 후 다른 명령창에서 서버 프로그램을 실행시킴
클라이언트가 입력한 문자열에서 끝의 공백들을 ㅠ 제거한 후 서버로 전송함
// server
package ch14;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.charset.StandardCharsets;
public class UDPEchoServer {
public static void main(String[] args) throws Exception {
int srvPort = 1234;
int clntPort = 4321;
String sbye = "";
// 서버용 데이터그램 소켓 오브젝트 생성
DatagramSocket dgSocket = new DatagramSocket(srvPort);
System.out.println(" Server running...");
do {
// 수신 패킷 오브젝트 생성
DatagramPacket dgPacket = new DatagramPacket(new byte[100], 100);
// 패킷 수신
dgSocket.receive(dgPacket);
String msg = new String(dgPacket.getData(), 0, dgPacket.getLength());
msg = msg.stripTrailing(); // 문자열 뒤의 공백 삭제
System.out.printf("incoming message : %s message size : %d\n",msg,msg.length());
// 송신 패킷 오브젝트 생성
dgPacket = new DatagramPacket(msg.getBytes(StandardCharsets.UTF_8),msg.getBytes().length, dgPacket.getAddress(),clntPort);
// 패킷 송신
dgSocket.send(dgPacket);
sbye = msg; // 임시
} while (!sbye.endsWith("bye")); // bye 입력시 종료
dgSocket.close();
}
}
// client
package ch14;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPEchoClient {
public static void main(String[] args) throws IOException {
int srvPort = 1234;
int clntPort = 4321;
String sbye = "";
Scanner cin = new Scanner(System.in);
// 클라이언트용 데이터그램 소켓 오브젝트 생성
DatagramSocket dgSocket = new DatagramSocket(clntPort);
InetAddress remote_addr = InetAddress.getByName("127.0.0.1");
do {
System.out.print("message to be sent : ");
String msg = cin.nextLine().stripTrailing(); // 문자열 뒤의 공백 삭제
if(msg.length() == 0) continue;
// 송신 패킷 오브젝트 생성
DatagramPacket dgPacket = new DatagramPacket(msg.getBytes(), msg.getBytes().length, remote_addr, srvPort);
System.out.println("send message size : " + dgPacket.getData().length);
// 패킷 송신
dgSocket.send(dgPacket);
// 수신 패킷 오브젝트 생성 : 최대 65507바이트
dgPacket = new DatagramPacket(new byte[100], 100);
// 패킷 수신
dgSocket.receive(dgPacket);
msg = new String(dgPacket.getData(), 0, dgPacket.getLength());
msg = msg.stripTrailing(); // 문자열 뒤의 공백 삭제
System.out.printf("\nincoming message : %s message size : %d\n", msg, msg.length());
sbye = msg;
} while (!sbye.endsWith("bye")); // bye 입력시 종료
dgSocket.close();
}
}
결과

