You will be fine

<Socket> 4. Socket Programming 정리

by BFine
반응형

Socket Programming

1.1 TCP 소켓프로그래밍

  • 이 통신은 서버와 클라이언트 간의 1대1 소켓 통신이다.
  • 서버가 먼저 시행되어 클라이언트의 연결 요청을 기다리고 있어야한다.
  • 한포트에 하나의 서버 소켓 만 연결할 수 있다. (프로토콜이 다르면 같은 포드를 공유할 수 있다.)
  • TCP 통신 절차
    1. 서버는 서버 소켓으로 특정 포트의 클라이언트 연결요청을 처리할 준비를 한다.(listen)
    2. 클라이언트는 연결 서버 IP와 포트번호로 소켓을 생성해 서버에 연결 요청한다.
    3. 요청을 받은 서버는 새로운 소켓을 생성해 클라이어트의 소켓과 연결되도록 한다.(accept)
  • 자바에서는 SocketServerSocket 클래스를 지원한다.

1.1.1 Soket

  • Socket은 TCP 클라이언트 API 이고 원격 호스트에 접속할때 사용한다.
  • ServerSocket은 TCP 서버 API 이고 클라이언트 Socket들을 연결 승인한다.
  • TCP Sockets를 주고받는것은 I/O stream 통해서 이루어진다.
public class Server {
    public static void main(String[] args){
            try {
                ServerSocket serverSocket = new ServerSocket(7777);
                System.out.println("서버 실행중...");
 
                while (true){
                    Socket socket = serverSocket.accept();
                    DataInputStream in = new DataInputStream(socket.getInputStream());
                    String msg = in.readUTF();
                    System.out.println(msg);
 
                    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                    out.writeUTF("수신확인");
                    in.close();
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
} 
 
public class Client {
    public static void main(String[] args){
        try {
            Scanner sc = new Scanner(System.in);
            Socket socket = new Socket("localhost",7777);
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());
            out.writeUTF("전송");
            DataInputStream in = new DataInputStream(socket.getInputStream());
            System.out.println(in.readUTF());
 
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.0 1대1 채팅

  • 1대1 채팅을 하기 위해서는 Thread가 필요하다(메세지를 수신,송신 각각)
  • 이것은 작업을 독립적인 단위 로 나눈다는 의미로 볼 수 있다.
public class Server {
    Socket socket;
    DataInputStream in;
    DataOutputStream out;
    Scanner sc;
    ServerSocket serverSocket;
    public Server() {
        try {
            ServerSocket serverSocket = new ServerSocket(7777); // listen 상태
            socket = serverSocket.accept(); // connect 요청이 들어오면 연결
            in = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(socket.getOutputStream());
            sc = new Scanner(System.in);
            revMsg();
            sendMsg();
        } catch (IOException e) {
        }
    }
 
    public void revMsg(){
        new Thread(()->{
                try {
                    while (true) {
                        String msg = in.readUTF();
                        System.out.println("클라이언트 : "+msg);
                    }
                } catch (IOException e) {
                }
        }).start();
    }
    public void sendMsg(){
        new Thread(()->{
                try {
                    while (true) {
                        out.writeUTF(sc.nextLine());
                    }
                } catch (IOException e) {
                    close();
                }
        }).start();
    }
    public void close(){
            try {
                System.out.println("연결끊김");
                socket.close();
                serverSocket.close();
                in.close();
                out.close();
            } catch (IOException e) {
            }
    }
    public static void main(String[] args){
        new Server();
    }
}
public class Client {
    Socket socket;
    DataInputStream in;
    DataOutputStream out;
    Scanner sc;
    public Client() {
        try {
            this.socket = new Socket("localhost",7777); // 연결 요청
            in = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(socket.getOutputStream());
            sc = new Scanner(System.in);
            sendMsg();
            revMsg();
        } catch (IOException e) {
        }
    }
    public void close(){
        try {
          System.out.println("연결끊김");
            socket.close();
            in.close();
            out.close();
        } catch (IOException e) {
        }
    }
    public void revMsg(){
        new Thread(()->{
            try {
                while (true) {
                    String msg = in.readUTF();
                    System.out.println("서버 : "+msg);
                }
            } catch (IOException e) {
            }
        }).start();
    }
    public void sendMsg(){
        new Thread(()->{
            try {
                while (true) {
                    out.writeUTF(sc.nextLine());
                }
            } catch (IOException e) {
              close();
            }
        }).start();
    }
    public static void main(String[] args) {
        new Client();
    }
}

3.0 다중 클라이언트

  • Block 은 메서드가 실행될때까지 멈춰있는 것을 의미한다.
  • Block 상태일때는 다른작업이 진행되지 않기 때문에 멀티스레드를 활용한다.
  • 멀티스레드 로 클라이언트를 block을 피하기위해 하나의 실행 단위로 바꿔주어야 한다.

3.0.1 다중채팅 구현

  • 클라이언트가 메세지를 보내면 서버에서 모든 메서지를 보내주는 콘솔을 구현했다.
  • 작은 단위로 보면 클라이언트가 보낸 메세지는 서버가 다시보내주는 형태이다.
  • 그렇기 때문에 클라이언트 스레드안에서 개별스레드를 만들필요가 없었다.
  • 클라이언트는 1대1채팅과 다르게 메인스레드와 recieve 스레드 만으로 구현했다.
public class Server {
    Socket socket;
    Scanner sc;
    ServerSocket serverSocket;
    LinkedList<Socket> socketList;
    Map<Socket, Integer> socketMap;
    public Server() {
        try {
            serverSocket = new ServerSocket(7777); // listen 상태 소켓을 생성
            socketList = new LinkedList<>();
            socketMap = new HashMap<>();
            int id = 0; //아이디
            System.out.println("서버 실행");
                while (true) {
                  // 클라이언트가 다중으로 접속하기 위한 무한반복문
 
                    socket = serverSocket.accept();
                     // connect 요청이 들어오면 연결 (올때까지 block)
 
                    System.out.println("클라이언트 접속");
                    System.out.println(socket);
                    socketMap.put(socket,++id);
                    socketList.add(socket);
 
                    // 클라이언트마다 스레드를 생성
                    // Thread가 없을경우 readUTF() 메서드에서 block이 발생하기 때문에 독립적으로 분할한다.  
                    new Thread(()->{
                        try {
                            DataInputStream in = new DataInputStream(socket.getInputStream());
                            revMsg(in,socket);
                        } catch (IOException e) {
                        }
                    }).start();
                }
        } catch (IOException e) {
        }
    }
    public void revMsg(DataInputStream in,Socket client){
            try {
                while (true) {
                    String msg = in.readUTF();
 
                    if(!msg.equals("")) {
                      sendMsg(client,msg);
                    }
                }
            } catch (IOException e) {
            }
    }
    public void sendMsg(Socket client,String msg){
      Integer id = socketMap.get(client);
      socketList.stream().forEach(so->{
        try {
 
          DataOutputStream ou = new DataOutputStream(so.getOutputStream());
          ou.writeUTF(id+"번님 : "+msg);
 
        } catch (IOException e) {
       }
      });
    }
    public static void main(String[] args){
        new Server();
    }
}
public class Client {
    Socket socket;
    DataInputStream in;
    DataOutputStream out;
    Scanner sc;
    public Client() {
        try {
            this.socket = new Socket("localhost",7777); // 연결 요청
            in = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(socket.getOutputStream());
            sc = new Scanner(System.in);
 
            revMsg();
            sendMsg();
            // 위의 두개의 메서드의 순서를 바꾸면 block이 발생한다.
 
 
        } catch (IOException e) {
        }
    }
    public void revMsg(){
        new Thread(()->{
            try {
                while (true) {
                    String msg = in.readUTF();
                    System.out.println(msg);
                }
            } catch (IOException e) {
            }
        }).start();
    }
    public void sendMsg(){
            try {
                while (true) {
                  String msg = sc.nextLine();
                  out.writeUTF(msg);
                }
            } catch (IOException e) {
              close();
            }
    }
    public static void main(String[] args) {
        new Client();
    }
}

출처

반응형

'공부(2018~2019) - 스킨변경전 > Socket' 카테고리의 다른 글

<Socket> 5. WebSocket 정리  (2) 2019.05.21
<Socket> 3. Network Programming 정리  (0) 2019.05.08
<Socket> 2. I/O Stream 정리  (0) 2019.05.07
<Socket> 1. Thread 정리  (0) 2019.05.05

블로그의 정보

57개월 BackEnd

BFine

활동하기