41. statfull 방식
한번 접속하면 종료할때까지 계속 반복 -클라이언트 작업 누적 가능
접속된 상태 계속 유지 - 서버 자원 점유 - 많은 클라이언트 접속을 유지할 수 없음
42. stateless 방식
접속 - 응답 - 접속 끊기
매번 접속시간 길어짐. 클라이언트 작업 유지 어려움
응답 후 끊기 때문에 서버 자원 덜 사용.
더 많은 동시 접속 가능
1. stateful
calcclient1 | calcserver 1 |
1. 연결 -> 2. 요청-> (반복) 5. quit |
3. 계산 4. 응답 <- |
package bitcamp.test;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CalcClient1 {
public static void main(String[] args) throws Exception{
try(
//Socket socket = new Socket("localhost", 8888);
//DataOutputStream out = new DataOutputStream(socket.getOutputStream());
//DataInputStream in = new DataInputStream(socket.getInputStream());
Scanner keyscan = new Scanner(System.in)) {
System.out.print("계산식> ");
String expr = keyscan.nextLine();
Pattern pattern = Pattern.compile("[0-9]+|\\p{Punct}"); // 0부터 9까지 숫자 하나, +는 1개 이상이라는 뜻 또는 연산 집합 중 1개
Matcher matcher = pattern.matcher(expr);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
}
//regular expression
<stateful 방식>
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//Stateful 방식으로 통신하기
public class CalcClient1 {
static Pattern pattern = Pattern.compile("[0-9]+|\\p{Punct}"); // 0부터 9까지 숫자 집합 중 하나, +는 1개 이상이라는 뜻 또는 연산 집합 중 1개
public static void main(String[] args) throws Exception{
try(
Socket socket = new Socket("localhost", 8888);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream());
Scanner keyscan = new Scanner(System.in)) {
while(true) {
System.out.print("계산식> ");
String input = keyscan.nextLine();
if (input.equals("quit")){
out.writeUTF("quit");
break;
}
String[] values = parseExpression(input);
out.writeUTF(values[1]);
out.writeInt(Integer.parseInt(values[0]));
out.writeInt(Integer.parseInt(values[2]));
String result = in.readUTF();
System.out.printf("결과: %s\n", result);
}
}
}
public static String[] parseExpression(String expr) {
Matcher matcher = pattern.matcher(expr);
ArrayList<String> values = new ArrayList<>();
while (matcher.find()) {
values.add(matcher.group());
}
return values.toArray(new String[] {});
}
}
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class CalcServer1 {
public static void main(String[] args)throws Exception {
try(ServerSocket serverSocket = new ServerSocket(8888)) {
System.out.println("서버실행!");
try (Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
InetSocketAddress sockAddr = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.printf("%s(%d) 클라이언트 접속! \n",
sockAddr.getHostName(), sockAddr.getPort());
while (true) {
String op = in.readUTF();
if (op.equals("quit")) {
break;
}
int a = in.readInt();
int b = in.readInt();
switch (op) {
case "+" : out.writeUTF(String.format("%d", a + b)); break;
case "-" : out.writeUTF(String.format("%d", a - b)); break;
case "*" : out.writeUTF(String.format("%d", a * b)); break;
case "/" : out.writeUTF(String.format("%d", a / b)); break;
case "%" : out.writeUTF(String.format("%d", a % b)); break;
default : out.writeUTF("지원하지 않는 연사자 입니다.");
}
}
}
}
}
}
<stateless 방식>
웹서버는 stateless 방식임
번호표 : session id
번호표의 작업: session
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//Stateless 방식으로 통신하기
public class CalcClient2 {
static Pattern pattern = Pattern.compile("[0-9]+|\\p{Punct}"); // 0부터 9까지 숫자 집합 중 하나, +는 1개 이상이라는 뜻 또는 연산 집합 중 1개
public static void main(String[] args) {
try( Scanner keyscan = new Scanner(System.in)) {
while(true) {
System.out.print("계산식(예: +3)> ");
String input = keyscan.nextLine();
if (input.equals("quit")){
break;
}
Expression expr = null;
try {
expr = parseExpression(input);
} catch (ExpressionParseException e) {
System.out.println(e.getMessage());
continue;
}
try (
Socket socket = new Socket("localhost", 8888);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream())) {
out.writeUTF(expr.op);
out.writeInt(expr.value);
String result = in.readUTF();
System.out.printf("결과: %s\n", result);
}
}
} catch (Exception e) {
System.out.println("서버 통신오류");
}
}
public static Expression parseExpression(String expr) throws ExpressionParseException {
try {
Matcher matcher = pattern.matcher(expr);
ArrayList<String> values = new ArrayList<>();
while (matcher.find()) {
values.add(matcher.group());
}
if(values.size() != 2) {
throw new Exception("계산식이 옳지 않습니다.");
}
Expression obj =new Expression();
obj.op = values.get(0);
obj.value= Integer.parseInt(values.get(1));
return obj;
} catch (Exception e) {
throw new ExpressionParseException(e); //Exception 상속 받은 클래스 : 예외 클래스. 아무것도 안 한 메서드지만 ,, 어떤 이유로 예외가 발생했는지 알 수 있어서 사용
}
}
static class Expression {
String op;
int value;
}
}
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class CalcServer2 {
public static void main(String[] args) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
System.out.println("서버 실행!");
while (true) {
processRequest(serverSocket.accept());
}
}
}
static void processRequest(Socket socket) {
InetSocketAddress sockAddr = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.printf("%s(%d) 클라이언트 접속!\n",
sockAddr.getHostString(), sockAddr.getPort());
try (Socket s = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
int result = 0;
String op = in.readUTF();
if (op.equals("quit")) {
return;
}
int value = in.readInt();
switch (op) {
case "+": result += value; break;
case "-": result -= value; break;
case "*": result *= value; break;
case "/": result /= value; break;
case "%": result %= value; break;
default: out.writeUTF("지원하지 않는 연산자입니다!");
}
out.writeUTF(String.format("%d", result));
} catch (Exception e) {
System.out.printf("%s(%d) 클라이언트 통신 오류!\n",
sockAddr.getHostString(), sockAddr.getPort());
}
}
}
Stateless 방식 + Session으로 통신하기 (uuid 추가)
UUID(Universally Unique IDentifier)는 네트워크상에서 고유성을 보장하는 ID를 만들기 위한 표준 규약이다
클라이언트앱
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.UUID;
//Stateless 방식 + Session으로 통신하기
public class CalcServer3 {
// 클라이언트 작업 결과를 보관할 저장소
static HashMap <String,Integer> resultMap = new HashMap<>();
public static void main(String[] args) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
System.out.println("서버 실행!");
while (true) {
processRequest(serverSocket.accept());
}
}
}
static void processRequest(Socket socket) {
InetSocketAddress sockAddr = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.printf("%s(%d) 클라이언트 접속!\n",
sockAddr.getHostString(), sockAddr.getPort());
try (Socket s = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
int result = 0;
String uuid = in.readUTF();
if(uuid.length()==0) {
//클라이언트가 처음 접속했다면, 클라이언트 식별 번호를 생성한다.
uuid = UUID.randomUUID().toString();
} else {
// 처음 접속이 아니라면, 이전에 접속했을 때 수행한 작업 결과를 가져온다.
resultMap.get(uuid);
}
String op = in.readUTF();
if (op.equals("quit")) {
return;
}
int value = in.readInt();
switch (op) {
case "+": result += value; break;
case "-": result -= value; break;
case "*": result *= value; break;
case "/": result /= value; break;
case "%": result %= value; break;
default: out.writeUTF("지원하지 않는 연산자입니다!");
}
//작업 결과를 저장소에 보관한다.
resultMap.put(uuid, result);
out.writeUTF(uuid);
out.writeUTF(String.format("%d", result));
} catch (Exception e) {
System.out.printf("%s(%d) 클라이언트 통신 오류!\n",
sockAddr.getHostString(), sockAddr.getPort());
}
}
}
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//Stateless 방식 + Session으로 통신하기
public class CalcClient3 {
static Pattern pattern = Pattern.compile("[0-9]+|\\p{Punct}"); // 0부터 9까지 숫자 집합 중 하나, +는 1개 이상이라는 뜻 또는 연산 집합 중 1개
public static void main(String[] args) {
String uuid = "";
try( Scanner keyscan = new Scanner(System.in)) {
while(true) {
System.out.print("계산식(예: +3)> ");
String input = keyscan.nextLine();
if (input.equals("quit")){
break;
}
Expression expr = null;
try {
expr = parseExpression(input);
} catch (ExpressionParseException e) {
System.out.println(e.getMessage());
continue;
}
try (
Socket socket = new Socket("localhost", 8888);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream())) {
out.writeUTF(uuid);
out.writeUTF(expr.op);
out.writeInt(expr.value);
uuid = in.readUTF();
String result = in.readUTF();
System.out.printf("결과: %s\n", result);
} catch (Exception e) {
System.out.println("서버 통신오류");
}
}
}
}
public static Expression parseExpression(String expr) throws ExpressionParseException {
try {
Matcher matcher = pattern.matcher(expr);
ArrayList<String> values = new ArrayList<>();
while (matcher.find()) {
values.add(matcher.group());
}
if(values.size() != 2) {
throw new Exception("계산식이 옳지 않습니다.");
}
Expression obj =new Expression();
obj.op = values.get(0);
obj.value= Integer.parseInt(values.get(1));
return obj;
} catch (Exception e) {
throw new ExpressionParseException(e); //Exception 상속 받은 클래스 : 예외 클래스. 아무것도 안 한 메서드지만 ,, 어떤 이유로 예외가 발생했는지 알 수 있어서 사용
}
}
static class Expression {
String op;
int value;
}
}
Thread 방식
stasteless 보다 더 정확하게 멀티태스킹이 됨 .
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//Stateful 방식으로 통신하기
public class CalcClient1x {
static Pattern pattern = Pattern.compile("[0-9]+|\\p{Punct}"); // 0부터 9까지 숫자 집합 중 하나, +는 1개 이상이라는 뜻 또는 연산 집합 중 1개
public static void main(String[] args) {
try(
Socket socket = new Socket("localhost", 8888);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream());
Scanner keyscan = new Scanner(System.in)) {
while(true) {
System.out.print("계산식(예: +3)> ");
String input = keyscan.nextLine();
if (input.equals("quit")){
out.writeUTF("quit");
break;
}
try {
Expression expr = parseExpression(input);
out.writeUTF(expr.op);
out.writeInt(expr.value);
String result = in.readUTF();
System.out.printf("결과: %s\n", result);
} catch (ExpressionParseException e) {
System.out.println("계산식이 옳지 않습니다.");
}
}
} catch (IOException e) {
System.out.println("서버 통신오류");
}
}
public static Expression parseExpression(String expr) throws ExpressionParseException {
try {
Matcher matcher = pattern.matcher(expr);
ArrayList<String> values = new ArrayList<>();
while (matcher.find()) {
values.add(matcher.group());
}
if(values.size() != 2) {
throw new Exception("계산식이 옳지 않습니다.");
}
Expression obj =new Expression();
obj.op = values.get(0);
obj.value= Integer.parseInt(values.get(1));
return obj;
} catch (Exception e) {
throw new ExpressionParseException(e); //Exception 상속 받은 클래스 : 예외 클래스. 아무것도 안 한 메서드지만 ,, 어떤 이유로 예외가 발생했는지 알 수 있어서 사용
}
}
static class Expression {
String op;
int value;
}
}
package bitcamp.test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class CalcServer1x{
public static void main(String[] args) throws Exception {
class RequestAgent extends Thread {
Socket socket;
public RequestAgent(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// main 스레드와 별개로 동작할 작업을 두는 곳
processRequest(socket);
}
}
try (ServerSocket serverSocket = new ServerSocket(8888)) {
System.out.println("서버 실행!");
while (true) {
System.out.println("클라이언트 연결을 기다리는 중!");
new RequestAgent(serverSocket.accept()).start();
System.out.println("클라이언트 요청을 RequestAgent에게 위임함!");
}
}
}
static void processRequest(Socket socket) {
InetSocketAddress sockAddr = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.printf("%s(%d) 클라이언트 접속!\n",
sockAddr.getHostString(), sockAddr.getPort());
try (Socket s = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
int result = 0;
while (true) {
String op = in.readUTF();
if (op.equals("quit")) {
break;
}
int value = in.readInt();
switch (op) {
case "+": result += value; break;
case "-": result -= value; break;
case "*": result *= value; break;
case "/": result /= value; break;
case "%": result %= value; break;
default: out.writeUTF("지원하지 않는 연산자입니다!");
}
out.writeUTF(String.format("%d", result));
}
} catch (Exception e) {
System.out.printf("%s(%d) 클라이언트 통신 오류!\n",
sockAddr.getHostString(), sockAddr.getPort());
}
}
}
Thred가 몰까 ,, ?
'[네이버클라우드] 클라우드 기반의 개발자 과정 7기 > 웹프로그래밍' 카테고리의 다른 글
[NC7기-57일차(7월14일)] - 웹프로그래밍 38일차 (0) | 2023.07.14 |
---|---|
[NC7기-56일차(7월13일)] - 웹프로그래밍 37일차 (0) | 2023.07.13 |
[NC7기-54일차(7월11일)] - 웹프로그래밍 35일차 (0) | 2023.07.11 |
[NC7기-53일차(7월10일)] - 웹프로그래밍 34일차 (0) | 2023.07.10 |
[NC7기-52일차(7월7일)] - 웹프로그래밍 33일차 (0) | 2023.07.07 |