JAVA/Java 기초

서버의 동시 요청 처리.java

john_ 2023. 2. 1. 12:42
728x90

2023.01.31 - [JAVA/Java 기초] - 네트워크 기초(IP, TCP, UDP).java

 

네트워크 기초(IP, TCP, UDP).java

네트워크 네트워크 : 여러 컴퓨터들을 통신 회선으로 연결한 것 LAN(Local Area Network) : 가정, 회사, 건물, 특정영역에 존재하는 컴퓨터 들을 연결 하는것, 근거리 통신 : 스위치, 게이트웨이, 모뎀,

less-go.tistory.com

 

이전글에서 계속됩니다.


서버의 동시 요청 처리

  • 일반적으로 서버는 다수의 클라이언트와 통신합니다.
  • 서버는 클라이언트들로 부터 동시에 요청을 받아서 처리하고,
  • 처리결과를 개별 클라이언트로 보내줍니다.

  • accept()와 recieve()를 제외한 요청 처리 코드를 별도의 스레드에서 작업합니다.

  • 스레드를 처리할 때 클라이언트의 폭증으로 인한 서버의 과도한 스레드 생서응ㄹ 방지하기 위해 스레드풀을 사용하는것이 바람직합니다.


TCP EchoServer 동시 요청 처리

  • 스레드풀을 이용해서 클라이언트의 요청을 동시에 처리합니다.

TCP EchoServer구현 : (스레드풀 적용, 10명)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService; // 스레드풀 (스레드의 갯수 제한)
import java.util.concurrent.Executors;

public class EchoServer {
	private static ServerSocket serverSocket = null;
	private static ExecutorService excutorService = Executors.newFixedThreadPool(10);
	
	public static void main(String[] args) {
		
		System.out.println("------------------------------------------");
		System.out.println("서버를 종료하려면 q를 입력하고 Enter 키를 입력 하세요.");
		System.out.println("------------------------------------------");
		
		//TCP 서버 시작
		startServer();
		
		//키보드 입력
		Scanner sc = new Scanner(System.in);
		while(true) {
			String key = sc.nextLine();
			if(key.toLowerCase().equals("q")) {
				break;
			}
		}
		sc.close();
		
		stopServer();
	}
	
	public static void startServer() {
		//작업 스레드 정의
		Thread thread = new Thread() {
			@Override
			public void run() {
				try {
					//ServerSocket 생성 및 Port 바인딩
					serverSocket = new ServerSocket(50001);
					System.out.println("[서버] 시작됨");
					
					while(true) {
						//연결수락
						Socket socket = serverSocket.accept();
						
						excutorService.execute(()-> {
							try {
								//연결된 클라이언트 정보 얻기
								InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
								System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");
								
								DataInputStream dis = new DataInputStream(socket.getInputStream());
								String message = dis.readUTF();
								
								DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
								dos.flush();
								System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);
								
								//연결 끊기
								socket.close();
								System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음");
								
							}catch (IOException e) {
							}
						});
					}
				}catch(IOException e) {
					System.out.println("[서버] " + e.getMessage());
				}
			}
		};
		//스레드 시작
		thread.start();
	}
	
	public static void stopServer() {
		try {
			//ServerSocket을 닫고 port 언바인딩
			serverSocket.close();
			System.out.println("[서버] 종료됨");
		}catch(IOException e1) {}
	}
}

 


UDP NewsServer 동시 요청 처리

  • 스레드풀을 이용해서 클라이언트의 요청을 동시에 처리

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NewsServer {

	private static DatagramSocket datagramSocket = null;
	private static ExecutorService executorService = Executors.newFixedThreadPool(10);

		public static void main(String[] args) throws Exception{
		System.out.println("-----------------------------------------");
		System.out.println("서버를 종료하려면 q를 입력하고 Enter키를 입력 하세요.");
		System.out.println("-----------------------------------------");

		//UDP 서버 시작
		startServer();
		
		Scanner sc = new Scanner(System.in);
		while(true) {
			String key = sc.nextLine();
			if(key.toLowerCase().equals("q")) {
				break;
			}
		}
		sc.close();
		
		//UDP 서버  종료
		stopServer();
	}
		
	public static void startServer() {
		// 작업 스레드 정의
		Thread thread = new Thread() {
			@Override
			public void run() {
				try {
					datagramSocket = new DatagramSocket(50001);
					System.out.println("[서버] 시작됨");
					
					while(true) {
						// 클라이언트에서 보내는 데이터를 받을 DatagramPacket을 생성
						DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
						//클라이언트로부터 데이터를 받으면 활성화가 됩니다.
						//receive : 대기상태 -> 데이터받음 -> 활성화
						datagramSocket.receive(receivePacket);
						
						executorService.execute(()-> {
							try {
								//클라이언트가 보낸 데이터를 스트링 형태로 변환
								String newsKind = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
								
								//클라이언트의 IP와 port 얻기
								SocketAddress socketAddress = receivePacket.getSocketAddress();
								
								//10개의 뉴스를 클라이언트로 전송
								for(int i = 0; i<=10; i++) {
									String data = newsKind + ": 뉴스" + i;
									byte[] bytes = data.getBytes("UTF-8");
									DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
									datagramSocket.send(sendPacket);
								}
							}catch (Exception e) {
							}
						});
					}
				} catch (Exception e) {
					System.out.println("[서버] " + e.getMessage());
				}
			}
		};
		//스레드 시작
		thread.start();
	}
	
	public static void stopServer() {
		//DatagramSocket을 닫고 Port 언바인딩
		datagramSocket.close();
		System.out.println("[서버] 종료됨");
	}
}

 

 


 

 

728x90

'JAVA > Java 기초' 카테고리의 다른 글

TCP 채팅 프로그램.java  (0) 2023.02.01
JSON 데이터형식.java  (0) 2023.02.01
네트워크 기초(IP, TCP, UDP).java  (0) 2023.01.31
기본 타입 스트림.java  (0) 2023.01.31
요소 커스텀 집계.java  (0) 2023.01.30