입출력을 이용한 채팅프로그램

hyunn·2021년 8월 8일
0

Java-basic

목록 보기
24/26
post-thumbnail

다른 사람과 연결되는 Server Client 프로그램

MyServer.java 작성

public class MyServer {
    //bad code close 철저히
    public static void main(String[] args) throws Exception{

        //ServerSocket은 손님을 기다리는 역할
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("Ready...");

        while (true) {
            //손님이 오면 accept => socket 생성 = client와 연결된 연락책?
            Socket client = serverSocket.accept();
            System.out.println(client);

            OutputStream out = client.getOutputStream();

            File file = new File("C:\\zzz\\aaa.jpg");

            //아래 4줄이 있어서 웹구현 가능해지는 것
            //HTTP 헤더
            out.write(new String("HTTP/1.1 200 OK\r\n").getBytes());
            out.write(new String("Cache-Control: private\r\n").getBytes());
            out.write(new String("Content-Length: "+file.length()+"\r\n").getBytes());
            out.write(new String("Content-Type: image/jpeg\r\n\r\n").getBytes());

            //out.write(97);
            InputStream fin = new FileInputStream("C:\\zzz\\aaa.jpg");

            byte[] buffer = new byte[1024*8]; //data 담을 계란판 buffer

            while (true) {
                int count = fin.read(buffer);  //몇 개나 새로운 data 읽었는지
                if (count == -1) { break; }    //새로운 data없으면 -1 => break
                out.write(buffer, 0, count);   //buffer의 내용물을 맨 앞부터 새로 읽은 개수만큼만 write
            }//end while

            //fin.close();
            out.close();
            client.close(); 
            //연결여부만 확인하고 바로 종료
        }//end while
    }
}



MyClient.java 작성

public class MyClient {
    //bad code
    public static void main(String[] args) throws Exception {
        
        Socket socket = new Socket("192.168.0.0", 9999);
        System.out.println(socket);

        InputStream in = socket.getInputStream();
        FileOutputStream fos = new FileOutputStream("C:\\zzz\\get.jpg");

        byte[] buffer = new byte[1024*8]; //data 담을 바가지

        while (true) {
            int count = in.read(buffer);  //몇 개나 새로운 data 읽었는지
            if (count == -1) { break; }  //새로운 data없으면 -1 => break
            fos.write(buffer, 0, count); //buffer의 내용물을 맨 앞부터 새로 읽은 개수만큼만 write
        }//end while
        
        fos.close();
        socket.close();
    }
}



단점

받는 파일이 뭔지 모름
원하는 파일만 받을 수 XX 보내주는 파일만 받을 수 있음

해결

파일이름 + 파일 데이터 따로 => 프로토콜 = 약속
웹에서 프로토콜 => HTTP.

해당 프로토콜에 맞게해야 주고받기 가능

실행 순서

MyServer 먼저 실행 후 Ready확인하고 MyClient 실행

  1. Server :

    ​ Ready...

  2. Client :

    ​ Socket[addr=/192.168.0.0,port=9999,localport=6774]

  3. Server :

    ​ Ready...

    ​ Socket[addr=/192.168.0.0,port=6774,localport=9999]

Server는 while loop로 계속 돌고있기때문에 빨간네모 Stop 눌러서 종료시켜줘야함



close의 위치

아직 데이터를 다 보내지 못한 상황에서 close하면 연결 끊기는 문제
fin -> out -> client였을때 문제 발생함
close는 꼭 해줘야하지만 그 타이밍도 중요하다 너무 빨리해도 문제 안해도 문제인것

현재 방식은 한번 접속하고 종료되고 한번 접속하고 종료되고 형식

=> 나중에 while과 multi-thread 를 이용해 해결 가능



프로토콜에는?

순서 / 구조 결정되어있음

클라이언트가 보내고 = Request

서버가 응답 = Response

HTTP -> stateless 무상태

처음부터 끝까지 연결된상태에서 => stateful = 연결지속형

ex.게임서버





1:1 채팅 프로그램

OneToOneServer.java 작성

public class OneToOneServer {
    //bad code
    public static void main(String[] args) throws Exception {
        Scanner keyScanner = new Scanner(System.in);
        
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("Ready...");

        //서버는 먼저 읽고 클라이언트는 계속 보냄
        //클라이언트가 보내는 메세지 읽으려면 몇바이튼지 알아야되는데 모름 
        // => 알기위해 Scanner사용
        //Scanner는 엔터(\n) 전까지 읽어들임

        Socket client = serverSocket.accept();
        System.out.println("Client connected...");

        //대부분의 경우 client가 먼저 전송함
        // = 서버는 읽어오기 먼저
        InputStream in = client.getInputStream();
        OutputStream out = client.getOutputStream();
        Scanner inScanner = new Scanner(in);  //InputStream과 연결된 scanner

        for (int i = 0; i < 100; i++) {
            String line = inScanner.nextLine();
            //뭘 원하는지 읽기
            System.out.println(line);

            String myMsg = keyScanner.nextLine()+"\n";
            out.write(myMsg.getBytes());
        }

        //다 썼으면 close 닫아주기
        inScanner.close();
        in.close();
        client.close();
        serverSocket.close();
    }
}



OneToOneClient.java 작성

public class OneToOneClient {
    //bad code
    public static void main(String[] args) throws Exception {
        Scanner keyScanner = new Scanner(System.in);
        Socket socket = new Socket("192.168.0.0", 9999);

        System.out.println("Connected...");

        //server로 보내야하니까 OutputStream
        OutputStream out = socket.getOutputStream();
        InputStream in = socket.getInputStream();
        Scanner inScanner= new Scanner(in);

        //문자열을 byte[]로 바꿔서 out.write(바이트배열)
        //Server 에선 읽을때 scanner 사용

        //for loop로 i회수 도는만큼 채팅 가능
        for (int i = 0; i < 100; i++) {
            
            String msg = keyScanner.nextLine() + "\n";
            //\n을 사용해줘야 server의 scanner가 끊어읽을 수 있음
            //안쓰면 인식불가 scanner가 끊을 수 없어서!

            out.write(msg.getBytes());
            System.out.println("----------------------------------");
            System.out.println(inScanner.nextLine());
        }

        out.close();
        socket.close();
    }
}

단점!!

반드시 받아야만 보낼 수 있고 받지않으면 보낼 수 없음, 연속으로 보내는거 불가능
=> 해결 : Thread 사용
현재 상황에선 여럿이서 불가능

한번 연결되면 for끝날때까지 끊을 수 없음
=> 해결 : 사용자가 서로 다이렉트로 말고 서버에 중계자역할 시키면?
연결 안맺고있다가 메세지 보낼때만 잠깐 연결될 수 있음

image image



Buffer

파일 입출력을 빠르게하는 방법

buffer 존재 1024*8

속도 비교 용량이 큰 파일 복사 속도 비교




계속해서 연결을 받고 끊고 반복하는 채팅서버

EchoServer.java 생성

public class EchoServer {
    //bad code
    public static void main(String[] args) throws Exception {
        
        Map<String, String[]> map = new HashMap<>();

        map.put("kor", new String[]{"불고기", "비빔밥"});
        map.put("jap", new String[]{"초밥", "라멘"});
        map.put("wes", new String[]{"피자", "파스타"});
        map.put("chn", new String[]{"짜장면", "짬뽕"});

        //서버소켓 준비
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("Ready....");
        //루프 시작
        while(true) {

            //연결 accept() Socket
            Socket socket = serverSocket.accept();
            System.out.println(socket.getInputStream());

            //클라이언트가 보낸 메시지 읽기
            //연결되자마자 보내게 되어있음
            InputStream in = socket.getInputStream();
            Scanner inScanner = new Scanner(in);

            String msg = inScanner.nextLine();
            System.out.println(msg); //kor, jap
            String[] arr = map.get(msg);

            //읽은 메세지를 다시 전송
            String sendMsg = null;

            if (arr == null) {
                sendMsg = "메뉴를 다시 선택하세요.\n";
            } else {
                int idx = (int) (Math.random() * arr.length);
                sendMsg = msg + ": " + arr[idx] + "\n";
            }

            OutputStream out = socket.getOutputStream();

            out.write(sendMsg.getBytes());
            out.flush(); //내용물을 한번에 밀어내는 역할

            out.close();
            inScanner.close();
            in.close();
            socket.close();
            //소켓 연결 종료
        }//end while
    }
}



EchoClient.java 생성

public class EchoClient {
    public static void main(String[] args) throws Exception {
        Scanner keyScanner = new Scanner(System.in);

        while (true) {
            System.out.println("Choice Your Menu");
            String msg = keyScanner.nextLine();

            if (msg.equalsIgnoreCase("exit")) {
                System.out.println("\n--End--"); break;
            }

            //지연연결 - 연결을 계속 미루다가 필요할때만 연결하고 끊기
            Socket socket = new Socket("192.168.0.53", 9999);
            InputStream in = socket.getInputStream();
            Scanner inScanner = new Scanner(in);
            OutputStream out = socket.getOutputStream();

            String sendMsg = msg +"\n";
            out.write(sendMsg.getBytes()); //전송 완료
            
            System.out.println(inScanner.nextLine());

            //한번 연결 후에 다 닫고 반복
            out.close();
            inScanner.close();
            in.close();
            socket.close();

        }//end while
    }
}



결과

image image

server에는 client에서 입력한 값이 계속해서 쌓이고

client에는 입력한 값에 해당하는 map arraylist의 메뉴 중 하나가 불러와지게 됨





0개의 댓글

관련 채용 정보