자바/네트워킹

소켓 프로그래밍: TCP와 UDP(2)

백_곰 2022. 5. 2. 10:42

3-3. 소켓 프로그래밍을 이해하기 위한 예제(3)

: 예제(2)에서 했던 코드를 Socekt 클래스에 정의된 getPort()와 getLocalPort()로 수정한 예제이다.

 

package Networking;
import java.net.*;
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;

public class Exercise008 {
	public static void main(String args[]) {
ServerSocket serverSocket = null;
		
		try {
			// 서버소켓을 생성하여 7777번 포트와 결합(bind)시킨다.
			serverSocket = new ServerSocket(7777);
			System.out.println(getTime()+"서버가 준비되었습니다.");

		} catch(IOException e) {
			e.printStackTrace();
		}
		
		while(true) {
			try {
				// 서버소켓
				System.out.println(getTime()+"연결요청을 기다립니다.");
				Socket socket = serverSocket.accept();
				System.out.println(getTime()+ socket.getInetAddress() + "로부터 연결요청이 들어왔습니다.");
				
				System.out.println("getPort():"+socket.getPort());
                System.out.println("getLocalPort():" +socket.getLocalPort());

				// 소켓의 출력스트림을 얻는다.
				OutputStream out = socket.getOutputStream();
				DataOutputStream dos = new DataOutputStream(out);

				// 원격 소켓(remote socket)에 데이터를 보낸다.
				dos.writeUTF("[Notice] Test Message1 from Server.");
				System.out.println(getTime()+"데이터를 전송했습니다.");

				// 스트림과 소켓을 닫아준다.
				dos.close();
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} // while
	} // main

	// 현재시간을 문자열로 반환하는 함수
	static String getTime() {
		SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
		return f.format(new Date());
	}
} // class

( getPort()가 반환하는 값은 상대편 소켓의 포트이다. )

( getLocalPort()는 소켓 자신이 사용하는 포트이다. )

 

( 이를 통해 알 수 있는 것은 서버 소켓이 7777번 포트를 사용하고 있어도, 서버 소켓이 아닌 소켓은

7777번 포트를 사용할 수 있다는 것이다. )

 

( 클라이언트 프로그램의 소켓이 사용하는 포트는 사용가능한 임의의 포트가 선택된다. )

 

 

 

 

3-4. 소켓 프로그래밍을 이해하기 위한 예제(4)

: 클라이언트 프로그램으로부터 5초동안 아무런 요청이 없다면 서버를 닫는 예제이다.

 

package Networking;
import java.net.*;
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;

public class Exercise009 {
	public static void main(String args[]) {
		ServerSocket serverSocket = null;
		
		try {
			// 서버소켓을 생성하여 7777번 포트와 결합(bind)시킨다.
			serverSocket = new ServerSocket(7777);
			System.out.println(getTime()+"서버가 준비되었습니다.");

		} catch(IOException e) {
			e.printStackTrace();
		}
		
		while(true) {
			try {
				// 서버소켓
				System.out.println(getTime()+"연결요청을 기다립니다.");

				// 요청대기시간을 5초로 설정한다. 
				// 5초동안 접속요청이 없으면 SocketTimeoutException이 발생한다.
				serverSocket.setSoTimeout(5*1000);
				Socket socket = serverSocket.accept();
				System.out.println(getTime()+ socket.getInetAddress() + "로부터 연결요청이 들어왔습니다.");

				// 소켓의 출력스트림을 얻는다.
				OutputStream out = socket.getOutputStream();
				DataOutputStream dos = new DataOutputStream(out);

				// 원격 소켓(remote socket)에 데이터를 보낸다.
				dos.writeUTF("[Notice] Test Message1 from Server.");
				System.out.println(getTime()+"데이터를 전송했습니다.");

				// 스트림과 소켓을 닫아준다.
				dos.close();
				socket.close();
			} catch (SocketTimeoutException  e) {
			     System.out.println("지정된 시간동안 접속요청이 없어서 서버를 종료합니다.");
				System.exit(0);
			} catch (IOException e) {
				e.printStackTrace();
			}
		} // while
	} // main

	// 현재시간을 문자열로 반환하는 함수
	static String getTime() {
		SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
		return f.format(new Date());
	}
} // class

 

( setTimeout(int timeout)을 사용하여 대기시간을 지정할 수 있다. )

( 만약 지정한 대기시간이 지난다면, accept()에서 SocketTimeoutException이 발생하므로 Catch문을

적절히 처리할 수 있다. )

 

 

 

 

3-5. 소켓 프로그래밍을 이해하기 위한 예제(5)

: 여러 개의 쓰레드를 생성해서 클라이언트의 요청을 동시에 처리하도록 하는 예제이다.

 

package Networking;

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 Exercise010 implements Runnable{
	ServerSocket serverSocket;
	Thread[] threadArr;

	public static void main(String args[]) {
		// 5개의 쓰레드를 생성하는 서버를 생성한다.
		Exercise010 server = new Exercise010(5);
		server.start();
	} // main
	
	public Exercise010(int num) {
		try {
			// 서버소켓을 생성하여 7777번 포트와 결합(bind)시킨다.
			serverSocket = new ServerSocket(7777);
			System.out.println(getTime()+"서버가 준비되었습니다.");

			threadArr = new Thread[num];
		} catch(IOException e) {
			e.printStackTrace();
		}
	}

	public void start() {
		for(int i=0; i < threadArr.length; i++) {
			threadArr[i] = new Thread(this);
			threadArr[i].start();
		}
	}

	public void run() {
		while(true) {
			try {
				System.out.println(getTime()+ "가 연결요청을 기다립니다.");

				Socket socket = serverSocket.accept();
				System.out.println(getTime()+ socket.getInetAddress() + "로부터 연결요청이 들어왔습니다.");

				// 소켓의 출력스트림을 얻는다.
				OutputStream out = socket.getOutputStream();
				DataOutputStream dos = new DataOutputStream(out);

				// 원격 소켓(remote socket)에 데이터를 보낸다.
				dos.writeUTF("[Notice] Test Message1 from Server.");
				System.out.println(getTime()+"데이터를 전송했습니다.");

				// 스트림과 소켓을 닫아준다.
				dos.close();
				socket.close();
		    } catch (IOException e) {
				e.printStackTrace();
			}
		} // while	
	} // run

	// 현재시간을 문자열로 반환하는 함수
	static String getTime() {
		String name = Thread.currentThread().getName();
		SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");

		return f.format(new Date()) + name ;
	}
} // class

 

( 이처럼 클라이언트의 수가 많을 때는 쓰레드를 이용해서 클라이언트의 요청을 병렬적으로 처리하는 것이 좋다. )

 

 

 

 

다음장

소켓 프로그래밍: TCP와 UDP(3) (tistory.com)

 

소켓 프로그래밍: TCP와 UDP(3)

 

kind-coding.tistory.com