<Network Programming 강의 요약>
데이터를 전달하기 전에 미리 연결 설정
한 번 연결되면 반복적으로 데이터 전송
처리율이 100%
포트 0번에서 소켓을 연다
- DatagramSocket socket = new DatagramSocket(0);
- 0으로 임의의 여유분 로컬 포트를 지정
try(DatagramSocket socket = new DatagramSocket(0)) {
// 서버와 메시지 교환
}catch(IOException e){
System.err.println("Could not bind to port 0");
}
소켓 옵션 설정
- socket.setSoTimeout(10000);
송신용 패킷을 준비한다.
- InetAddress remoteHost = InetAddress.getByName("time.nist.gov");
수신용 패킷을 준비한다.
- byte[] data = new byte[1024];
서버와 패킷을 보내고 받는다
- socket.send(request)
서버가 보낸 응답 패킷으로부터 데이터를 추출해서 문자열로 변환해 사용한다.
- String result = new String(response.getData(), 0, response.getLength(), "US-ASCII");
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPDaytimeClient1 {
private static final int PORT = 13;
private static final String HOSTNAME = "time.nist.gov";
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(0)) {
socket.setSoTimeout(10000);
InetAddress host = InetAddress.getByName(HOSTNAME);
DatagramPacket request = new DatagramPacket(new byte[1], 1, host, PORT);
DatagramPacket response = new DatagramPacket(new byte[1024], 1024);
socket.send(request);
socket.receive(response);
String result = new String(response.getData(), 0, response.getLength(), "US-ASCII");
System.out.println(result);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Date;
public class UDPDaytimeServer1 {
public final static int DEFAULT_PORT = 13;
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket(DEFAULT_PORT);
DatagramPacket packet = new DatagramPacket(new byte[1], 1);
while (true) {
socket.receive(packet);
System.out.println("Request from " + packet.getAddress() + " : " + packet.getPort());
byte[] outBuffer = (new Date().toString() + " from JNU UDP Daytime server").getBytes();
packet.setData(outBuffer);
packet.setLength(outBuffer.length);
socket.send(packet);
}
} catch (IOException ex) {
System.err.println(ex);
}
}
}
import java.net.*;
import java.util.Date;
import java.util.logging.*;
import java.io.*;
public class UDPDaytimeServer2 {
private final static int PORT = 13;
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(PORT)) {
while (true) {
try {
DatagramPacket request = new DatagramPacket(new byte[1024], 0, 1024);
socket.receive(request);
String daytime = new Date().toString();
byte[] data = daytime.getBytes("MS949");
DatagramPacket response = new DatagramPacket(data, data.length, request.getAddress(),
request.getPort());
socket.send(response);
System.out.println(daytime + " " + request.getAddress());
} catch (IOException | RuntimeException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
} catch (IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
다르고, 주소와 포트는 메소드로 얻는다. 왜??
2-byte unsigned byte로 표현되며 최대 값은 65535, 단위는 바이트
UDP Datagram은 IP Datagram에 캡슐화된다
- UDP Datagram에 IP Header가 붙어 IP Datagram을 구성한다.
그렇지만 IP Datagram 헤더의 Length 필드 역시 2바이트로 최대 값은 65535
UDP Datagram의 최대 길이는 IP 헤더용 20바이트와 UDP 헤더용 8바이트를 제외한 65535 - (20 + 8) = 65507 바이트지만, IP 헤더에는 옵션을 40바이트까지 허용하므로 길이는 65535 - (20 + 8 + 40) = 65467이다.
이론적으로 Datagram의 최대 길이는 65507 이지만 현실적으로는 이보다 훨씬 작게 대개는 8KB로 제한되며 보통의 응용프로그램은 512바이트로 처리한다.
UDP Datagram의 최소 길이는 8 바이트
- 극단적으로 데이터를 포함하지 않고 헤더만 전송하는 것도 허용한다.
UDP Datagram의 길이는 IP Datagram의 길이에 의존적이므로 사실 이 필드는 무의미하다고 할 수 있다.
import java.net.*;
public class UDPReceiver {
public static void main (String args[ ]) {
byte[] buffer = new byte[8192];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
}
}
String s = "This is a Test";
byte[] data = s.getBytes("UTF-8");
try {
InetAddress addr = InetAddress.getByName("www.ibiblio.org");
int port = 7;
DatagramPacket dp = new DatagramPacket(data, data.length, addr, port);
// 이 위치에서 데이터그램을 전송한다
} catch (IOException e) { }
송신을 위해 DatagramPacket을 생성했을 경우에는 목적지 포트
(수신용은 DatagramPacket input = new DatagramPacket(new byte[512], 512); 형식의 패킷임을 참고)
import java.io.*;
import java.net.*;
public class UDPDatagramExample {
public static void main(String[] args) {
String s = "This is a test.";
try {
byte[] data = s.getBytes("UTF-8");
InetAddress ia = InetAddress.getByName("www.ibiblio.org");
int port = 7;
DatagramPacket dp = new DatagramPacket(data, data.length, ia, port);
System.out.println("이 패킷을 보낼 곳의 주소는 " + dp.getAddress() + ", 포트는 " + dp.getPort());
System.out.println("패킷의 길이는 " + dp.getLength() + " 바이트임");
System.out.println("보낼 데이터는 " + new String(dp.getData(), dp.getOffset(), dp.getLength(), "UTF-8"));
} catch (UnknownHostException | UnsupportedEncodingException ex) {
System.err.println(ex);
}
}
}
결과 :
// 이 위치에서 bigArray에 데이터를 넣는다.
int offset = 0
DatagramPacket dp = new DatagramPacket(bigArray, offset, 512);
int bytesSent = 0;
while(bytesSent < bigArray.length) {
socket.send(dp); // 하나의 데이터그램을 전송
bytesSent += dp.getLength(); // 보낸 바이트 수 누적
int bytesToSend = bigArray.length - bytesSent; // 잔여 바이트 수
int size = (byteToSend > 512) ? 512 : bytesToSend;
dp.setData(bigArray, bytesSent, size)
}
String s = "Really Important Message";
byte[] data = s.gerBytes("UTF-8");
DatagramPacket dp = new DatagramPacket(data, data.length);
dp.setPort(2000);
String network = "128.238.5.";
for (int host = 1; host < 255; host++) {
try{
InetAddress remote = InetAddress.getByName(network + host);
dp.setAddress(remote);
socket.send(dp);
}catch(Exception e) {}
}
DatagramPacket input = new DatagramPacket(new byte[8192], 8192);
socket.receive(input);
DatagramPacket output = new DatagramPacket("Hello there".getBytes("UTF-8"), 11);
SocketAddress address = input.getSocketAddress();
output.setAddress(address);
socket.send(output);
임의의 포트에 바인드되는 DatagramSocket을 생성
클라이언트용 소켓 생성
DatagramSocket이 설정된 로컬 포트를 알려면 getLocelport() 이용
사용 예
public static void main(String[] args) {
try {
DatagramSocket theClient = new DatagramSocket();
} catch(SocketException e) {
}
}
DatagramSocket 생성을 시도하여 예외가 발생하면 포트가 이미 사용중이라고 결론 내린다.
UDP 포트 사용 예
- 30,000 번대는 RPC(Remote Procedure Call)가 사용
import java.net.*;
import java.net.*;
public class UDPPortScanner {
public static void main(String[] args) {
for (int port = 1024; port <= 65535; port++) {
try {
// 포트 i에서 실행되는 서버가 있을 경우
// 다음 줄은 예외를 발생시키고 catch 블록으로 떨어진다
DatagramSocket server = new DatagramSocket(port);
server.close();
} catch (SocketException ex) {
System.out.println("There is a server on port " + port + ".");
}
}
}
}
결과 :
public void send(DatagramPacket dp) throws IOException
- DatagramPacket이 생성되고, DatagramSocket이 열리면 소켓의 send() 메소드에 패킷을 넘김으로써 데이터를 전송
예 : theSocket.send(theOutput);
UDP는 신뢰성이 없는 프로토콜이므로 전송된 패킷이 목적지에 도달하지 않더라도 예외가 발생하지 않는다.
단, 다음과 같은 경우에는 IOException 발생
- 호스트의 네트워크 소프트웨어가 지원하는 것보다 큰 데이터그램을 보내려고 하면 Exception 발생
Security Manager가 통신을 불허할 때 SecurityException 발생
- DatagramPacket 객체를 send 한다.
import java.net.*;
import java.io.*;
public class UDPDiscardClient {
public final static int PORT = 9;
public static void main(String[] args) {
String hostname = args.length > 0 ? args[0] : "localhost";
try (DatagramSocket theSocket = new DatagramSocket()) {
InetAddress server = InetAddress.getByName(hostname);
BufferedReader userInput
= new BufferedReader(new InputStreamReader(System.in));
while (true) {
String theLine = userInput.readLine();
if (theLine.equals(".")) break;
byte[] data = theLine.getBytes();
DatagramPacket theOutput = new DatagramPacket(data, data.length, server, PORT);
theSocket.send(theOutput);
} // end while
} catch (IOException ex) {
System.err.println(ex);
}
}
import java.net.*;
import java.io.*;
public class UDPDiscardServer {
public final static int PORT = 9;
public final static int MAX_PACKET_SIZE = 65507;
public static void main(String[] args) {
byte[] buffer = new byte[MAX_PACKET_SIZE];
try (DatagramSocket server = new DatagramSocket(PORT)) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
try {
server.receive(packet);
String s = new String(packet.getData(), 0, packet.getLength(), “MS949");
System.out.println(packet.getAddress() + " at port " + packet.getPort() + " says " + s);
// 다음 패킷 수신을 위해 길이를 리셋한다 # (받고 나면 길이가 줄어들어 있다!!)
packet.setLength(buffer.length);
} catch (IOException ex) {
System.err.println(ex);
}
} // end while
} catch (SocketException ex) {
System.err.println(ex);
}
}
}
TCP 소켓과 달리 UDP 소켓은 통신 상대가 누구인가는 중요하지 않다.
그러나 종종 상대를 고정해야 하는 경우가 있다. 게임 같은 경우가 여기에 해당된다. 이럴 때는 게임에 참여한 사람으로부터의 데이터그램만 기다려야 한다.
- 이 기능은 데이터를 주고 받을 상대를 특정인으로 고정하는 것이다.
public void connect(InetAddress remoteHost, int remotePort)
- TCP와 같은 성질의 연결이 아니며 지정된 호스트하고만 패킷을 주고 받을 것임을 설정
- 다른 호스트로 데이터그램을 전송하려 시도하면 IllegalArgumentException 발생
- 다른 호스트나 포트에서 전달받은 데이터는 폐기
public void disconnect()
- 연결 종료
public int getPort()
- 연결되어 있는 소켓의 포트번호 return
public InetAddress getInetAddress()
- 연결되어 있는 소켓의 원격지 주소 반환
public SocketAddress getRemoteSocketAddress()
- 연결되어 있는 소켓의 원격지 주소 반환
이 클라이언트는 특정 주소와 포트에서 실행되는 UDP 서버에게 자신의 주소와 포트만 알려주면 된다.
- 클라이언트는 서버의 주소와 포트가 들어 있고 데이터 부분이 비어 있는 UDP 패킷을 보낸다.
세 개의 private 필드
- bufferSize : return 받을 패킷을 담을 버퍼의 크기
<강조> socket.setSoTimeout(int)
- 설정된 시간을 초과하여도 응답이 없으면 catch(InterruptedIOException ex) {} 이 실행된다.
poke()
- UDP 클라이언트가 돌려받는 데이터는 바이트 배열 형태이므로 반환타입을 byte[]로 설정하며 null로 초기화된다.
실행 형식
- java UDPPoke host port
예 :
- C:>java UDPPoke rama.poly.edu 13
Tue May 30 11:42:07 2021
import java.io.*;
import java.net.*;
public class UDPPoke {
private int bufferSize; // in bytes
private int timeout; // in milliseconds
private InetAddress host;
private int port;
public UDPPoke(InetAddress host, int port, int bufferSize, int timeout) {
this.bufferSize = bufferSize;
this.host = host;
if (port < 1 || port > 65535) {
throw new IllegalArgumentException("Port out of range");
}
this.port = port;
this.timeout = timeout;
}
public UDPPoke(InetAddress host, int port, int bufferSize) {
this(host, port, bufferSize, 30000);
}
public UDPPoke(InetAddress host, int port) {
this(host, port, 8192, 30000);
}
public byte[] poke() {
try (DatagramSocket socket = new DatagramSocket(0)) {
DatagramPacket outgoing = new DatagramPacket(new byte[1], 1, host, port);
socket.connect(host, port);
socket.setSoTimeout(timeout);
socket.send(outgoing);
DatagramPacket incoming = new DatagramPacket(new byte[bufferSize], bufferSize);
// 다음 라인은 응답을 받을 때까지 중단됨
socket.receive(incoming);
int numBytes = incoming.getLength();
byte[] response = new byte[numBytes];
System.arraycopy(incoming.getData(), 0, response, 0, numBytes);
return response;
} catch (IOException ex) {
return null;
}
}
public static void main(String[] args) {
InetAddress host;
int port = 0;
try {
host = InetAddress.getByName(args[0]);
port = Integer.parseInt(args[1]);
} catch (RuntimeException | UnknownHostException ex) {
System.out.println("Usage: java UDPPoke host port");
return;
}
try {
UDPPoke poker = new UDPPoke(host, port);
byte[] response = poker.poke();
if (response == null) {
System.out.println("No response within allotted time");
return;
}
String result = new String(response, "US-ASCII");
System.out.println("Response = " + result);
} catch (UnsupportedEncodingException ex) {
// Really shouldn't happen
ex.printStackTrace();
}
}
}
import java.net.*;
import java.util.*;
public class UDPTimeClient {
public final static int PORT = 37;
public final static String DEFAULT_HOST = "localhost";
public static void main(String[] args) {
InetAddress host;
try {
if (args.length > 0) {
host = InetAddress.getByName(args[0]);
} else {
host = InetAddress.getByName(DEFAULT_HOST);
}
} catch (RuntimeException | UnknownHostException ex) {
System.out.println("Usage: java UDPTimeClient [host]");
return;
}
UDPPoke poker = new UDPPoke(host, PORT);
byte[] response = poker.poke();
if (response == null) {
System.out.println("No response within allotted time");
return;
} else if (response.length != 4) {
System.out.println("Unrecognized response format");
return;
}
// Time 프로토콜은 1900년 기준
// Java의 Date 클래스는 1970년 기준
// 다음 값은 이들 사이의 시간 차
long differenceBetweenEpochs = 2208988800L;
long secondsSince1900 = 0;
for (int i = 0; i < 4; i++) {
secondsSince1900 = (secondsSince1900 << 8) | (response[i] & 0x000000FF);
}
long secondsSince1970 = secondsSince1900 - differenceBetweenEpochs;
long msSince1970 = secondsSince1970 * 1000;
Date time = new Date(msSince1970);
System.out.println(time);
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Date;
public class UDPTimeServer2 {
public final static int PORT = 37;
public static void main(String[] args) {
DatagramSocket dsock = null;
long differenceBetweenEpochs = 2208988800L;
try{
System.out.println("UDP Time Server 클라이언트의 접속을 기다림 " + new Date());
dsock = new DatagramSocket(PORT);
String line = null;
while(true){
// 받기
byte[] buffer = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
dsock.receive(receivePacket);
Date now = new Date();
long msSince1970 = now.getTime();
long secondsSince1970 = msSince1970/1000;
long secondsSince1900 = secondsSince1970
+ differenceBetweenEpochs;
byte[] time = new byte[4];
time[0]
= (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24);
time[1]
= (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);
time[2]
= (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);
time[3] = (byte) (secondsSince1900 & 0x00000000000000FFL);
System.out.println(receivePacket.getAddress() + "으로 현재시간을 전송합니다.");
DatagramPacket sendPacket = new DatagramPacket(time, time.length, receivePacket.getAddress(), receivePacket.getPort());
dsock.send(sendPacket);
} // while
}catch(Exception ex){
System.out.println(ex);
}finally{
if(dsock != null)
dsock.close();
}
} // main
} // class
import java.io.*;
import java.net.*;
public abstract class UDPServer implements Runnable {
private final int bufferSize; // in bytes
private final int port;
private volatile boolean isShutDown = false;
public UDPServer(int port, int bufferSize) {
this.bufferSize = bufferSize;
this.port = port;
}
public UDPServer(int port) {
this(port, 8192);
}
public void run() {
byte[] buffer = new byte[bufferSize];
try (DatagramSocket socket = new DatagramSocket(port)) {
socket.setSoTimeout(10000); // check every 10 seconds for shutdown
while (true) {
if (isShutDown)
return;
DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
try {
socket.receive(incoming);
this.respond(socket, incoming);
} catch (SocketTimeoutException ex) {
shutDown();
} catch (IOException ex) {
ex.printStackTrace();
}
} // while
} catch (SocketException ex) {
System.err.println("Could not bind to port: " + port);
ex.printStackTrace();
}
}
public abstract void respond(DatagramSocket socket, DatagramPacket request) throws IOException;
public void shutDown() {
this.isShutDown = true;
}
}
import java.net.*;
public class UDPFastDiscardServer extends UDPServer {
public final static int DEFAULT_PORT = 9;
public UDPFastDiscardServer() {
super(DEFAULT_PORT);
}
public static void main(String[] args) {
UDPServer server = new UDPFastDiscardServer();
Thread t = new Thread(server);
t.start();
}
public void respond(DatagramSocket socket, DatagramPacket request) {
}
}
import java.net.*;
import java.io.*;
import java.util.*;
/*
* 이 서버는 추상클래스 UDPServer를 상속하여 구성
*/
public class UDPDaytimeServer3 extends UDPServer {
public final static int DEFAULT_PORT = 13;
public UDPDaytimeServer3() throws SocketException {
super(DEFAULT_PORT);
}
public void respond(DatagramSocket ds, DatagramPacket packet) {
try {
Date now = new Date();
String response = now.toString() + "\r\n";
byte[] data = response.getBytes("ASCII");
DatagramPacket outgoing = new DatagramPacket(data, data.length, packet.getAddress(), packet.getPort());
System.out.println("Response will be sent to " + packet.getAddress() + "-" + packet.getPort());
ds.send(outgoing);
} catch (IOException e) {
System.err.println(e);
}
}
public static void main(String[] args) {
try {
UDPDaytimeServer3 server = new UDPDaytimeServer3();
new Thread(server).start();
} catch (SocketException e) {
System.err.println(e);
}
}
}
import java.io.*;
import java.net.*;
public class UDPEchoServer extends UDPServer {
public final static int DEFAULT_PORT = 7;
public UDPEchoServer() {
super(DEFAULT_PORT);
}
@Override
public void respond(DatagramSocket socket, DatagramPacket packet) throws IOException {
DatagramPacket outgoing = new DatagramPacket(packet.getData(), packet.getLength(), packet.getAddress(), packet.getPort());
socket.send(outgoing);
}
public static void main(String[] args) {
UDPServer server = new UDPEchoServer();
Thread t = new Thread(server);
t.start();
}
}
//
// Example 12-12
//
import java.net.*;
public class UDPEchoClient {
public final static int PORT = 7;
public static void main(String[] args) {
String hostname = "localhost";
if (args.length > 0) {
hostname = args[0];
}
try {
InetAddress ia = InetAddress.getByName(hostname);
DatagramSocket socket = new DatagramSocket();
SenderThread sender = new SenderThread(socket, ia, PORT);
sender.start();
Thread receiver = new ReceiverThread(socket);
receiver.start();
} catch (UnknownHostException ex) {
System.err.println(ex);
} catch (SocketException ex) {
System.err.println(ex);
}
}
}
import java.io.*;
import java.net.*;
class SenderThread extends Thread {
private InetAddress server;
private DatagramSocket socket;
private int port;
private volatile boolean stopped = false;
SenderThread(DatagramSocket socket, InetAddress address, int port) {
this.server = address;
this.port = port;
this.socket = socket;
this.socket.connect(server, port);
}
public void halt() {
this.stopped = true;
}
public void run() {
try {
BufferedReader userInput
= new BufferedReader(new InputStreamReader(System.in));
while (true) {
if (stopped) return;
String theLine = userInput.readLine();
if (theLine.equals(".")) break;
byte[] data = theLine.getBytes("UTF-8");
DatagramPacket output
= new DatagramPacket(data, data.length, server, port);
socket.send(output);
Thread.yield();
}
} catch (IOException ex) {
System.err.println(ex);
}
}
}
import java.io.*;
import java.net.*;
class ReceiverThread extends Thread {
private DatagramSocket socket;
private volatile boolean stopped = false;
ReceiverThread(DatagramSocket socket) {
this.socket = socket;
}
public void halt() {
this.stopped = true;
}
@Override
public void run() {
byte[] buffer = new byte[65507];
while (true) {
if (stopped) return;
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
try {
socket.receive(dp); // <<강조>> Timeout이 설정되지 않아 무작정 기다린다.
String s = new String(dp.getData(), 0, dp.getLength(), "UTF-8");
System.out.println(s);
Thread.yield();
} catch (IOException ex) {
System.err.println(ex);
}
}
}
}
DatagramSocket 객체 생성
- DatagramSocket dsock = new DatagramSocket();
사용자로부터 문자열을 입력 받기 위한 스트림
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
전송 :
- 서버에게 전달할 바이트 배열, 배열 길이, InetAddress 객체, 포트번호로 DatagramPacket 객체 생성
받기 :
- 반송되는 DatagramPacket 객체를 읽어 들인다.
- byte [] buffer = new byte[line.getBytes().length];
- DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
- dsock.receive(receivePacket);
반송된 결과 출력 :
- DatagramPacket 을 통해 전달된 바이트 배열을 문자열로 변환하여 화면에 출력
- String msg = new String(receivePacket.getData(), 0, receivePacket.getData().length);
- System.out.println("전송 받은 문자열 = " + msg);
// UDP Echo 클라이언트
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class UDPSimpleEchoClient {
public static void main(String[] args) {
String ip = "localhost";
int port = 7;
InetAddress inetaddr = null;
try {
inetaddr = InetAddress.getByName(ip);
} catch (UnknownHostException e) {
System.out.println("잘못된 도메인이나 ip입니다.");
System.exit(1);
}
DatagramSocket dsock = null;
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
dsock = new DatagramSocket();
String line = br.readLine() ;
while( line != null){
if(line.equals("quit")) break; // 사용자 입력의 끝은 quit로 표시
// 보내기
DatagramPacket sendPacket = new DatagramPacket(line.getBytes(), line.getBytes().length, inetaddr, port);
dsock.send(sendPacket);
// 받기
byte[] buffer = new byte[line.getBytes().length];
DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
dsock.receive(receivePacket);
// 서버로부터 되받은 결과 출력
String msg =
new String(receivePacket.getData(), 0, receivePacket.getData().length);
System.out.println("Message from Echo server :" + msg);
// 사용자의 다음 입력을 받아 들인다
line = br.readLine();
} // end while
System.out.println("UDPEchoClient를 종료합니다.");
} catch(Exception ex){
System.out.println(ex);
}finally {
if(dsock != null) dsock.close();
}
} // end main()
} // end class
/*
* 패킷 상실로 인한 Timeout을 고려한 Echo 클라이언트
* echo 메시지를 보내고 받는다.
* 패킷이 정해진 시간 내 도착하지 않으면 5회 반복 시도한다.
*/
import java.net.*;
import java.io.*;
public class UDPEchoClientTimeout {
private static final int MAXTRIES = 5; // 최대 재전송 시도 횟수
public static void main(String[] args) throws IOException {
String server = "localhost";
InetAddress serverAddress = InetAddress.getByName(server);
byte[] message = "This is message from client.".getBytes();
int serverPort = 7;
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(3000); // <<강조>> 최대 대기시간 (milliseconds)
// Sending packet
DatagramPacket sendPacket = new DatagramPacket(message, message.length, serverAddress, serverPort);
// Receiving packet
DatagramPacket receivePacket = new DatagramPacket(new byte[message.length], message.length);
int tries = 0; // 패킷 상실 대비 시도 회수 저장
boolean receiveOK = false;
do {
socket.send(sendPacket); // 에코 문자열을 보낸다
try {
socket.receive(receivePacket); // 에코 응답 수신 시도
if (!receivePacket.getAddress().equals(serverAddress)) // 응답 출처 검사
throw new IOException("Received packet from an unknown source");
receiveOK = true; // <<강조>> 또는 SocketTimeoutException
} catch (InterruptedIOException e) { // 시간 내 받지 못함
tries += 1;
System.out.println("Timed out, " + (MAXTRIES - tries) + " time try...");
}
} while ((!receiveOK) && (tries < MAXTRIES));
if (receiveOK)
System.out.println("Message received from server: " + new String(receivePacket.getData()));
else
System.out.println("No response -- giving up.");
socket.close();
}
}
//
// 10%의 응답을 의도적으로 폐기
//
import java.net.*;
import java.io.*;
public class UDPSimpleEchoServer2{
protected DatagramSocket socket;
public UDPSimpleEchoServer2 (int port) throws IOException {
socket = new DatagramSocket (port);
}
public void execute () throws IOException {
while (true) {
DatagramPacket packet = receive();
System.out.print("Received message: ");
System.out.write(packet.getData());
System.out.println();
if (Math.random () < .9)
sendEcho (packet.getAddress (), packet.getPort (), packet.getData (), packet.getLength ());
else
System.out.println ("discarded");
}
}
protected DatagramPacket receive() throws IOException {
byte buffer[] = new byte[65535];
DatagramPacket packet = new DatagramPacket (buffer, buffer.length);
socket.receive (packet);
return packet;
}
protected void sendEcho(InetAddress address, int port, byte data[], int length) throws IOException {
DatagramPacket packet = new DatagramPacket (data, length, address, port);
socket.send (packet);
System.out.print("Sent message: ");
System.out.write(data);
System.out.println();
}
public static void main (String args[]) throws IOException {
UDPSimpleEchoServer2 echo = new UDPSimpleEchoServer2 (7);
System.out.println("Echo Server running on port 7 ......");
echo.execute ();
}
}