이것이 자바다 17일차 - Chapter19 네트워크 입출력

Seo-Faper·2023년 2월 1일
1

이것이 자바다

목록 보기
18/20
post-thumbnail

IP 주소 얻기

자바에서 네트워크 프로토콜을 다루는 법을 소개한다.
우선 집 주소라고 할 수 있는 IP를 얻는 방법은 다음과 같다.

package ch19.sec02;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressExample {
    public static void main(String[] args) {
        try{
            InetAddress local = InetAddress.getLocalHost();
            System.out.println("내 컴퓨터 IP 주소 : "+local.getHostAddress());

            InetAddress[] iaArr = InetAddress.getAllByName("www.naver.com");
            for(InetAddress remote : iaArr){
                System.out.println("www.naver.com 주소 : "+remote.getHostAddress());
            }
        }catch(UnknownHostException e){

        }

    }
}

java.net의 InetAddress를 통해 알아 낼 수 있다.

TCP 네트워킹

IP 주소로 프로그램들이 통신할 때는 약속된 데이터 전송 규약이 있다. 이것을 전송용 프로토콜이라고 부른다. 인터넷에서 전송용 프로토콜은 TCP와 UDP가 있다.

TCP는 3Way-handshaking으로 세션을 수립한다.

TCP 서버 만드는 법

package ch19.sec03.exam01;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ServerExample {

    private static ServerSocket serverSocket = null;
    public static void main(String[] args) {
        System.out.println("----------------------------------------------------");
        System.out.println("서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.");
        System.out.println("----------------------------------------------------");
        
        startServer();

        Scanner scanner = new Scanner(System.in);
        while (true){
            String key = scanner.nextLine();
            if(key.toLowerCase().equals("q")) break;
        }
        
        scanner.close();
        
        stopServer();
        
    }


    public static void startServer() {
        Thread thread = new Thread(){
            @Override
            public void run(){
                try{
                    serverSocket = new ServerSocket(50001);
                    System.out.println("[서버] 시작됨");

                    while (true){
                        System.out.println("\n[서버] 연결 요청을 기다림\n");
                        Socket socket = serverSocket.accept();

                        InetSocketAddress isa =
                                (InetSocketAddress) socket.getRemoteSocketAddress();
                        System.out.println("[서버]"+isa.getHostName()+"의 연결 요청을 수락함");

                        socket.close();
                        System.out.println("[서버] "+isa.getHostName()+"의연결을 끊음");
                    }
                }catch(IOException e){
                        System.out.println("[서버] "+e.getMessage());
                }
            }
        };
        thread.start();
    }
    private static void stopServer() {
        try{
            serverSocket.close();
            System.out.println("[서버] 종료됨.");
        }catch (IOException e){}
    }

}

TCP 클라이언트 만드는 법

package ch19.sec03.exam01;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientExample {
    public static void main(String[] args) {
        try{
            Socket socket = new Socket("localhost",50001);

            System.out.println("[클라이언트] 연결 성공");
            socket.close();
            System.out.println("[클라이언트] 연결 끊음");
        }catch(UnknownHostException e){
            //IP 표기 방법이 잘못되었을 때
        } catch (IOException e) {
            throw new RuntimeException(e);
            // 해당 포트의 서버에 연결할 수 없는 경우
        }

    }
}

입출력 스트림으로 데이터 주고 받기

클라이언트가 연결 요청 (connect())을 하고 서버가 연결 수락(accept())했다면 양쪽의 Socket 객체로부터 각각 입력 스트림과 출력 스트림을 얻을 수 있다.

UDP 네트워킹

UDP는 TCP와 다르게 일방적인 데이터 수신 방식으로 안정성이 떨어지는 대신 빠른 속도가 장점이다.

UDP는 말 그대로 User Datagram Protocal 이기 때문에 UDP 서버는 항상 클라이언트가 보낸 DatagramPacker를 받을 준비가 되어 있어야 한다.

package ch19.sec04;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.util.Scanner;

public class NewsServer extends Thread{
    private static DatagramSocket datagramSocket = null;

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

        startServer();
        Scanner sc = new Scanner(System.in);
        while (true){
            String key = sc.nextLine();
            if(key.toLowerCase().equals("q")) break;
        }
        sc.close();

        stopServer();
    }

    private static void stopServer() {
        datagramSocket.close();
        System.out.println("[서버] 종료됨");
    }

    private static void startServer() {
        Thread thread = new Thread(){

                @Override
                public void run() {
                    try {
                        //Datagram 생성 및 포트 바인딩
                        datagramSocket = new DatagramSocket(50001);
                        System.out.println("[서버] 시작됨");

                        while (true){
                            //클라이언트가 구독하고 싶은 뉴스 주제 얻기
                            DatagramPacket receivePacket = new DatagramPacket
                                    (new byte[1024],1024);
                            datagramSocket.receive(receivePacket);
                            String newsKind =
                                    new String(receivePacket.getData(),0,
                                            receivePacket.getLength(), "UTF-8");

                            //클라이언트의 IP와 PORT 얻기
                            SocketAddress socketAddress = receivePacket.getSocketAddress();

                            for(int i = 1; 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) {

                        System.out.println("[서버]"+e.getMessage());
                    }
                }
        };
        thread.start();
    }
}

서버를 이렇게 세팅한다.

package ch19.sec04;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class NewsClient {
    public static void main(String[] args) {
        try{
            //구독하고 싶은 뉴스 주제 보내기
            DatagramSocket datagramSocket = new DatagramSocket();
            String data = "정치";
            byte[] bytes = data.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(bytes,bytes.length,
            	new InetSocketAddress("localhost",50001));
            datagramSocket.send(sendPacket);

            while (true){
                //뉴스 받기
                DatagramPacket receivePacket = new DatagramPacket(new byte[1024],1024);
                datagramSocket.receive(receivePacket);

                //문자열로 변환
                String news = new String(receivePacket.getData(), 0,
                        receivePacket.getLength(), "UTF-8");
                System.out.println(news);
                //10번째 뉴스를 받으면 while 문 종료
                if(news.contains("뉴스10")){
                    break;
                }
            }
            datagramSocket.close();
        }catch (Exception e){

        }
    }
}

서버의 동시 요청 처리

일반적으로 서버는 다수의 클라이언트와 통신을 한다. 서버는 클라이언트들로부터 동시에 요청을 받아서 처리하고, 처리 결과를 개별 클라이언트로 보내 줘야 한다.
앞서 쓴 예제들은 모두 먼저 클라이언트의 요청을 처리한 후, 다음 클라이언트의 요청을 처리하도록 되어 있다.
이와 같은 방식은 먼저 연결한 클라이언트의 요청 처리 시간이 길어질수록 다음 클라이언트의 요청 처리 작업이 지연될 수 밖에 없다. 따라서 accept()와 receive()를 제외한 요청 처리 코드를 별도의 스레드에서 작업하는 것이 좋다.

package ch19.sec05.exam01;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
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 executorService =
            Executors.newFixedThreadPool(10);
    public static void main(String[] args) {

        System.out.println("----------------------------------------");
        System.out.println("서버를 종료하려면 q를 입력하고 Enter 키를 입력하세요.");
        System.out.println("----------------------------------------");

        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 = new ServerSocket(50001);
                    System.out.println("[서버] 시작됨");

                    while (true){
                        Socket socket = serverSocket.accept();
                        executorService.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.writeUTF(message);
                                dos.flush();

                                System.out.println("[서버] 받은 데이터를 다시 보냄: "+message);

                                socket.close();
                                System.out.println("[서버] "+isa.getHostName()+"의 연결을 끊음\n");

                            }catch(IOException e){

                            }
                        });
                    }
                }catch(Exception e){System.out.println("[서버] "+e.getMessage());}
            }
        };
        thread.start();
    }
    public static void stopServer(){
        try{
            serverSocket.close();
            executorService.shutdownNow();
            System.out.println("[서버] 종료됨");
        }catch(IOException e){

        }
    }
}

json 데이터 형식

네트워크로 전달하는 데이터가 복잡할 수록 구조화된 형식이 필요하다.
네트워크 통신에서 가장 많이 쓰는 형식은 JSON으로, 자바 뿐만 아니라 여러 곳에서 응용된다.

자바는 JSON을 편하게 만들기 위해 JSON 라이브러리를 제공한다.
다운로드

JSON 만드는 법

package ch19.sec06;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;

public class CreateJsonExample {
    public static void main(String[] args) throws IOException {
        JSONObject root = new JSONObject();

        root.put("id","winter");
        root.put("name","한겨울");
        root.put("age",25);
        root.put("student",false);

        JSONObject tel = new JSONObject();
        tel.put("home","02-123-1234");
        tel.put("mobile","010-123-1234");
        root.put("tel",tel);

        JSONArray skill = new JSONArray();
        skill.put("java");
        skill.put("c");
        skill.put("c++");
        root.put("skill",skill);

        String json = root.toString();

        System.out.println(json);

        Writer writer = new FileWriter("C:/Temp/member.json", Charset.forName("UTF-8"));
        writer.write(json);
        writer.flush();
        writer.close();
    }
}

지정된 경로에 member.json이 생성된다.

package ch19.sec06;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;

public class ParseJsonExample {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(
                new FileReader("C:/Temp/member.json", Charset.forName("UTF-8"))
        );
        String json = br.readLine();
        br.close();

        JSONObject root = new JSONObject(json);

        System.out.println("id: "+root.getString("id"));
        System.out.println("name: "+root.getString("name"));
        System.out.println("age: "+root.getInt("age"));
        System.out.println("student: "+root.getBoolean("student"));

        JSONObject tel = root.getJSONObject("tel");
        System.out.println("home: "+tel.getString("home"));
        System.out.println("mobile: "+tel.getString("mobile"));

        JSONArray skill = root.getJSONArray("skill");
        System.out.print ("skill: ");
        for(int i = 0; i<skill.length(); i++){
            System.out.print (skill.get(i)+", ");
        }

    }
}

BufferReader로 읽어서 스트림을 만들고 JSON 라이브러리로 가공할 수 있다.

TCP 채팅 프로그램 만들기

package ch19.sec07;

import java.net.ServerSocket;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ChatServer {
    ServerSocket serverSocket;
    ExecutorService threadPool = Executors.newFixedThreadPool(100);
    Map<String, SocketClient> chatRoom
            = Collections.synchronizedMap(new HashMap<>());
    
}

serverSocket은 클라이언트의 연결 요청을 수락하고, threadPool은 100개의 클라이언트가 동시에 채팅할 수 있도록 한다. cahtRoom은 통신용 SocketClient를 관리하는 동기화된 Map 이다.

    public void start() throws IOException{
        serverSocket = new ServerSocket(50001);
        System.out.println("[서버] 시작됨");

        Thread thread = new Thread(()->{
            try{
                while (true){
                    Socket socket = serverSocket.accept();
                    SocketClient sc = new SocketClient(this, socket);
                }
            }catch(Exception e){

            }

        });
        thread.start();

그리고 이어서 start() 메소드를 만들어 준다.
이 코드는 서버를 열어주는 역할을 한다.

    public void addSocketClient(SocketClient socketClient){
        String key = socketClient.chatName+"@"+socketClient.clientIp;
        chatRoom.put(key,socketClient);
        System.out.println("입장: "+key);
        System.out.println("현재 채팅자 수 : "+chatRoom.size()+"\n");
    }
    public void removeSocketClient(SocketClient socketClient){
        String key = socketClient.chatName+"@"+socketClient.clientIp;
        chatRoom.remove(key);
        System.out.println("나감: "+key);
        System.out.println("현재 채팅자 수 : "+chatRoom.size()+"\n");
    }
    

이어서 클라이언트가 접속하고 나가는 기능을 구현한다.

    public void setToAll(SocketClient sender, String message){
        JSONObject root = new JSONObject();
        root.put("clientIP",sender.ClientIP);
        root.put("clientName",sender.chatName);
        root.put("message",message);
        String json = root.toString();

        Collection<SocketClient> socketClients = chatRoom.values();
        for(SocketClient sc : socketClients){
            if(sc == sender) continue;
            sc.send(json);
        }
    }

그리고 접속한 모든 클라이언트에게 메세지를 보내는 메소드를 구현한다.

public void stop(){
        try{
            serverSocket.close();
            threadPool.shutdownNow();
            chatRoom.values().stream().forEach(e-> e.close());
        }catch (IOException e){}
    }

    public static void main(String[] args) {
        try{
            ChatServer chatServer = new ChatServer();
            chatServer.start();

            System.out.println("----------------------------------------");
            System.out.println("서버를 종료하려면 q를 입력하고 Enter 키를 입력하세요.");
            System.out.println("----------------------------------------");

            Scanner sc = new Scanner(System.in);
            while (true){
                String key = sc.nextLine();
                if(key.toLowerCase().equals("q")) break;
            }
            sc.close();
            chatServer.stop();
        }catch(IOException e){
            System.out.println("[서버] "+e.getMessage());
        }

    }

그리고 서버의 main을 만들어 준다.
그 다음은 SocketClient를 만들어 보자.

package ch19.sec07;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

public class SocketClient {
    ChatServer chatServer;
    Socket socket;
    DataInputStream dis;
    DataOutputStream dos;
    String clientIp;
    String chatName;
    public SocketClient(ChatServer chatServer, Socket socket){
        try{
            this.chatServer = chatServer;
            this.socket = socket;
            this.dis = new DataInputStream(socket.getInputStream());
            this.dos = new DataOutputStream(socket.getOutputStream());
            InetSocketAddress isa =
                    (InetSocketAddress) socket.getRemoteSocketAddress();
            this.clientIp = isa.getHostName();
            receive();
        }catch(IOException e){

        }


    }
}

기본적인 필드와 생성자를 만들어 준다. receive() 메소드는

    public void receive(){
        chatServer.threadPool.execute(()->{
            try{
                while (true){
                    String receiveJson = dis.readUTF();

                    JSONObject jsonObject = new JSONObject(receiveJson);
                    String command = jsonObject.getString("command");

                    switch (command){
                        case "incoming":
                            this.chatName = jsonObject.getString("data");
                            chatServer.sendToAll(this,"들어오셨습니다.");
                            chatServer.addSocketClient(this);
                            break;
                        case "message":
                            String message = jsonObject.getString("data");
                            chatServer.sendToAll(this,message);
                            break;
                    }
                }
            }catch(IOException e){
                chatServer.sendToAll(this,"나가셨습니다.");
                chatServer.removeSocketClient(this);
            }
        });
    }
    public void send(String json){
        try{
            dos.writeUTF(json);
            dos.flush();
        }catch (IOException e){

        }
    }
    public void close(){
        try{
            socket.close();
        }catch (IOException e){

        }
    }

클라이언트가 보낸 JSON 메세지를 읽는 역할을 한다. dis.readUTF()로 JSON을 읽고 command 값을 얻어낸다.
그 다음은 채팅 클라이언트를 만들면 된다.

package ch19.sec07;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class ChatClient {
    Socket socket;
    DataInputStream dis;
    DataOutputStream dos;
    String chatName;

    public void connect() throws IOException{
        socket = new Socket("localhost",50001);
        dis = new DataInputStream(socket.getInputStream());
        dos = new DataOutputStream(socket.getOutputStream());
        System.out.println("[클라이언트] 서버에 연결됨");
    }
}

receive() 메소드는 서버가 보낸 Json을 읽는 역할을 한다.

    public void receive(){
        Thread thread = new Thread(()->{
           try{
               while (true){
                   String json = dis.readUTF();
                   JSONObject root = new JSONObject(json);
                   String clientIp = root.getString("clientIp");
                   String chatName = root.getString("chatName");
                   String message = root.getString("message");
                   System.out.println("<"+chatName+"@"+clientIp+"> "+message);

               }
           }catch (Exception e){
                System.out.println("[클라이언트] 서버 연결 끊김");
                System.exit(0);
           }
        });
        thread.start();
    }
 public void send(String json) throws IOException{
        dos.writeUTF(json);
        dos.flush();
    }
    public void unconnect() throws IOException{
        socket.close();
    }

    public static void main(String[] args) {
        try{
            ChatClient chatClient = new ChatClient();
            chatClient.connect();
            Scanner sc = new Scanner(System.in);
            System.out.println("대화명 입력");
            chatClient.chatName = sc.nextLine();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("command","incoming");
            jsonObject.put("data",chatClient.chatName);
            String json = jsonObject.toString();
            chatClient.send(json);
            
            chatClient.receive();
            
            System.out.println("------------------------------------------");
            System.out.println("보낼 메세지를 입력하고 Enter");
            System.out.println("채팅을 종료하려면 q를 입력하고 Enter");
            System.out.println("------------------------------------------");
            while (true){
                String message = sc.nextLine();
                if(message.toLowerCase().equals("q")) break;
                else{
                    jsonObject = new JSONObject();
                    jsonObject.put("command","message");
                    jsonObject.put("data",message);
                    json = jsonObject.toString();
                    chatClient.send(json);

                }
            }
            sc.close();
            chatClient.unconnect();
        } catch (IOException e) {
            System.out.println("[클라이언트] 서버 연결 안됨");
        }
    }

연습문제

2번, Port도 있어야 합니다.

2번, 4번
TCP는 하나의 회선으로 통신하기 때문에 느리지만 정확하고 UDP는 여러 회선으로 전달하기 때문에 빠르지만 안정성이 떨어집니다.

new Socket("localhost",5001);


serverSocket.accept();

왼쪽 위 : InputStream
오른쪽 위 : OutputStream
왼쪽 아래 : OutputStream
오른쪽 아래 : InutStream

1: DatagramSocket
2: DatagramPacket
3: DatagramSocket
4: DatagramPacket
5: DatagramPacket

어차피 UDP는 DatagramSocket과 DatagramPacket으로 수발하기 때문에..

4번, 발신할 때는 send() 입니다.

이거는 앞서한 TCP 채팅 서버 만들기에서 조금만 변형하면 됩니다. 원리는 같으니까요.
서버 생성 -> 소켓 클라이언트 생성 -> receive()로 클라이언트한테 받은 JSON 처리하는 코드 작성 -> 클라이언트 생성 이렇게 만들려 합니다.

Product.java

package ch19.homework;


public class Product {
    private int no;
    private String name;
    private int price;
    private int stock;


    public Product() {

    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getStock() {
        return stock;
    }

    public void setStock(int stock) {
        this.stock = stock;
    }



}

ProductClient.java

package ch19.homework;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class ProductClient {
    private Socket socket;
    private DataInputStream dis;
    private DataOutputStream dos;
    private Scanner sc;

    public static void main(String[] args) {
        ProductClient productClient = new ProductClient();
        try{
            System.out.println("클라이언트 start()");
            productClient.start();
        }catch (IOException e){
            e.printStackTrace();
            productClient.stop();

        }
    }
    public void start() throws IOException {
        //서버 연결하기
        socket = new Socket("localhost", 50001);
        dis = new DataInputStream(socket.getInputStream());
        dos = new DataOutputStream(socket.getOutputStream());
        System.out.println("[클라이언트] 서버에 연결됨");

        sc = new Scanner(System.in);

        showProduct();

    }

    private void showProduct() throws IOException {
        System.out.println("[상품 목록]");
        System.out.println("-----------------------------------------------");
        System.out.println("no\t\tname\t\t\t\t\t\t\tprice\t\t\t\tstock");
        System.out.println("-----------------------------------------------");

        JSONObject request = new JSONObject();
        request.put("menu",0);
        request.put("data",new JSONObject());
        dos.writeUTF(request.toString());
        dos.flush();

        JSONObject response = new JSONObject(dis.readUTF());

        if(response.getString("status").equals("success")){
            JSONArray data = response.getJSONArray("data");
            for(int i = 0; i<data.length();i++){
                JSONObject product = data.getJSONObject(i);
                System.out.printf(
                        "%-6d%-30s%-15d%-10d\n",
                        product.getInt("no"),
                        product.getString("name"),
                        product.getInt("price"),
                        product.getInt("stock")
                );
            }
        }

        showMenu();
    }

    private void showMenu() throws IOException {
        System.out.println("-----------------------------------------------");
        System.out.println("메뉴 : 1. Create | 2. Update | 3. Delete | 4.Exit");
        System.out.print("선택 >");
        int sel = Integer.parseInt(sc.nextLine());

        if(sel==1)create();
        else if(sel==2) update();
        else if(sel==3) delete();
        else if(sel==4) exit();
    }

    private void exit() {
        stop();
    }

    private void delete() throws IOException {
        System.out.println("[상품 삭제]");
        System.out.print("상품 번호: ");
        int no = Integer.parseInt(sc.nextLine());

        //상품 수정 요청하기
        JSONObject data = new JSONObject();
        data.put("no", no);

        JSONObject request = new JSONObject();
        request.put("menu", 3);
        request.put("data", data);

        dos.writeUTF(request.toString());
        dos.flush();

        //응답 받기
        JSONObject response = new JSONObject(dis.readUTF());
        if(response.getString("status").equals("success")) {
            showProduct();
        }
    }

    private void update() throws IOException {
        System.out.println("[상품 수정]");
        Product product = new Product();
        System.out.print("상품 번호: ");
        product.setNo(Integer.parseInt(sc.nextLine()));
        System.out.print("이름 변경: ");
        product.setName(sc.nextLine());
        System.out.print("가격 변경: ");
        product.setPrice(Integer.parseInt(sc.nextLine()));
        System.out.print("재고 변경: ");
        product.setStock(Integer.parseInt(sc.nextLine()));


        JSONObject data = new JSONObject();
        data.put("no", product.getNo());
        data.put("name", product.getName());
        data.put("price", product.getPrice());
        data.put("stock", product.getStock());

        JSONObject request = new JSONObject();
        request.put("menu", 2);
        request.put("data", data);

        dos.writeUTF(request.toString());
        dos.flush();

        JSONObject response = new JSONObject(dis.readUTF());

        if(response.getString("status").equals("success")) {
            showProduct();
        }
    }

    private void create() throws IOException {
        System.out.println("[상품 생성]");
        Product product = new Product();
        System.out.print("상품 이름 : ");
        product.setName(sc.nextLine());
        System.out.print("상품 가격 : ");
        product.setPrice(Integer.parseInt(sc.nextLine()));
        System.out.print("상품 재고 : ");
        product.setStock(Integer.parseInt(sc.nextLine()));
        JSONObject data = new JSONObject();
        data.put("name", product.getName());
        data.put("price", product.getPrice());
        data.put("stock", product.getStock());

        JSONObject request = new JSONObject();
        request.put("menu", 1);

        request.put("data", data);

        dos.writeUTF(request.toString());
        dos.flush();

        JSONObject response = new JSONObject(dis.readUTF());
        if(response.getString("status").equals("success")) {
            showProduct();
        }
    }


    public void stop(){
        try{
            socket.close();
            sc.close();
        }catch(Exception e){
            System.out.println("[클라이언트] 종료");
        }
    }

}

ProductServer.java, SocketClient.java

package ch19.homework;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProductServer {
    private ServerSocket serverSocket;
    private ExecutorService threadPool;
    private List<Product> products;
    private int number;

    public static void main(String[] args) {
        ProductServer productServer = new ProductServer();
        try{
            productServer.start();
        }catch(IOException e){
            productServer.stop();
        }
    }
    public void start() throws IOException{
        serverSocket = new ServerSocket(50001);
        threadPool = Executors.newFixedThreadPool(100);
        products = new Vector<Product>();

        System.out.println("[서버] 시작됨");

        while (true){
            Socket socket = serverSocket.accept();
            SocketClient sc = new SocketClient(socket);
        }

    }
    public void stop(){
        try{
            serverSocket.close();
            threadPool.shutdownNow();
            System.out.println("[서버] 종료됨");
        } catch (IOException e) {

        }

    }
    public class SocketClient{
        private Socket socket;
        private DataInputStream dis;
        private DataOutputStream dos;
        public SocketClient( Socket socket){
            try{
                this.socket = socket;
                this.dis = new DataInputStream(socket.getInputStream());
                this.dos = new DataOutputStream(socket.getOutputStream());
            }catch(IOException e){

            }
        }
        public void receive(){
            threadPool.execute(()->{
                try{
                    while (true){
                        String receiveJson = dis.readUTF();

                        JSONObject request = new JSONObject(receiveJson);
                        int sel = request.getInt("menu");
                        
                        if(sel==0) list(request);
                        else if(sel==1) create(request);
                        else if(sel==2) update(request);
                        else if(sel==3) delete(request);
                    }
                }catch (IOException e){
                        close();
                }
            });
        }
        public void close(){
            try{
                socket.close();
            }catch (Exception e){

            }
        }

        private void update(JSONObject request) throws IOException {
            JSONObject data = request.getJSONObject("data");
            int no = data.getInt("no");
            for(int i= 0; i<products.size(); i++) {
                Product product = products.get(i);
                if(product.getNo() == no) {
                    product.setName(data.getString("name"));
                    product.setPrice(data.getInt("price"));
                    product.setStock(data.getInt("stock"));
                }
            }

            //응답 보내기
            JSONObject response = new JSONObject();
            response.put("status", "success");
            response.put("data", new JSONObject());
            dos.writeUTF(response.toString());
            dos.flush();
        }

        private void delete(JSONObject request) throws IOException {
            JSONObject data = request.getJSONObject("data");
            int no = data.getInt("no");
            for(int i = 0; i<products.size(); i++){
                if(products.get(i).getNo()== no) {
                    products.remove(i);
                    break;
                }
            }

            //응답 보내기
            JSONObject response = new JSONObject();
            response.put("status", "success");
            response.put("data", new JSONObject());
            dos.writeUTF(response.toString());
            dos.flush();
        }

        private void create(JSONObject request) throws IOException {

            JSONObject data = request.getJSONObject("data");
            Product product = new Product();
            product.setNo(++number);
            product.setName(data.getString("name"));
            product.setPrice(data.getInt("price"));
            product.setStock(data.getInt("stock"));
            products.add(product);

            JSONObject response = new JSONObject();
            response.put("status", "success");
            response.put("data", new JSONObject());
            dos.writeUTF(response.toString());
            dos.flush();
        }

        private void list(JSONObject request) throws IOException {

            JSONArray data = new JSONArray();
            for (Product p : products) {
                JSONObject product = new JSONObject();
                product.put("no", p.getNo());
                product.put("name", p.getName());
                product.put("price", p.getPrice());
                product.put("stock", p.getStock());
                data.put(product);
            }
            JSONObject response = new JSONObject();
            response.put("status", "success");
            response.put("data", data);
            dos.writeUTF(response.toString());
            dos.flush();
        }
    }
}
profile
gotta go fast

0개의 댓글