[자바]소켓 멀티 채팅
소켓은 아이피 정보와 포트 정보(포트 번호)로 이뤄진 클래스 PC와 PC가 통신 하려면 소켓을 통해 (IO) 한다.
소켓은 데이터 주고받아야 해서 각 소켓은 상대방의 정보를 알아야 한다.
1. Socket(소켓)이 만들어지는 과정(TCP 3-way HandShake)
서버쪽엔 소켓 말고 서버소켓이 만들어짐(별개의 개념) 서버 소켓은 통신 하기 위한 소켓이 아니라 서버쪽에만 만들어짐. 클라이언트로 부터 접속 받기 위해서만 만들어짐.
서버 소켓 만드려면 클라이언트가 접속하도록 포트 번호를 만들어줘야 된다.
서버소켓은 클라이언트가 접속하기 위해 출입문 만들어짐.
- 서버가 9000번 포트 열면 대기
- 클라이언트가 접속하려면?
- 클라가 서버 갈 때 자기 정보를 가지고 간다
- 그리고 포트가 열려서 나가야 한다.(클라이언트도 문 열고 나감)
2. JAVA에서 Socket(소켓) 만들기(ServerSocket, Socket, import java.net.*)
클라이언트도 내부적으로 포트 여는데 몇번이 열릴지는 모름
자기 정보가 접속 안하면 전혀 알 수 없다.
tpc,ip는 클라가 서버 접속시 그 정보를 반드시 자기 정보를 넘겨주게 된다. 그게 ip 정보, 포트 번호이다.
접속 시도시 자신의 정보도 넘어간다 이게 중요.
클라에 접속 되면 식별하는데 어디서 온지, 몇번 포트 열고 오는지 식별하는데 이 서버 소켓은 클라이언트의 접속을 대기함.
서버 소켓이 클라이언트 식별하면 하나의 다른 쪽으로 열고 소켓 하나 만듬(서버소켓은 통신 용이 아님, 통신하기 위해 다른 포트로 연결)
9001번도 몇번 포트 열릴지 모름.
클라이언트 식별하고 통신하기 위해 다른 쪽 포트 열어줌. 이걸 바인딩(연결시켜준다)이라고 한다.
클라 식별하고 바인딩 하는게 2번쨰고 소켓이 완전히 만들어짐. 이 소켓은 데이터 통신이 가능해짐. 이 소켓은 클라이언트와 통신이 가능해지고 이 소켓은 클라이언트 정보를 알아야 하므로 클라이언트 정보가 들어간다
서버에서 만들어진 소켓은 클라이언트 정보를 알고있다.
서버에서 소켓 만들어지면, 넘겨주는데 서버의 정보를 넘겨준다.
서버의 정보를 클라에 줘야 클라도 그걸 통해 서버에 통신 가능.
서버 소켓 만들어지고 정보 주면 이 클라이언트도 소켓 완성.
서버 정보 알고 있어야 되는데 이 정보를 알고 있어야 한다.
이게 3 핸드 쉐이킹의 기본(3-way HandShake)
소켓과 클라는 상대방의 정보를 알고 3핸드 쉐이킹을 한다
만약 클라가 하나 더있으면? 똑같이 하나 더한다.
소켓 정보 알고 클라 정보를 넘겨주며 서버 정보를 받아오고 통신을 한다.
자바 소켓에는 서버소켓, 소켓이 있고 쓰기 위해서는 import java.net을 사용해야 한다.
- 서버 소켓 만들어서 대기할 수 있는 9000번 포트를 만들어준다.
- 서버 입장에서 포트 열리면 접속했는지 어케 암?->누구는 계속 체크한다. 이게 서버소켓의 accept메소드가 (서버에 대기, 이게 중요) 블로킹 하면서 접속을 대기(블로킹 메서드라고도 한다)
- 접속하게 되면 식별한다.(클라이언트에 정보가 넘어오는데 이게 클라이언트 식별하고 정상적인 요청이면 수락, 아니면 거부)
- 통신 하도록 다른 포트를 열어서 바인딩 한다.
- 소켓은 클라이언트의 정보가 들어간다.
- 서버쪽도 클라이언트에 넘겨줘야 클라이언트도 서버에 정보를 전달이 가능하다.
근데 서버입장에서 클라이언트가 여러개 오면? 소켓 관리를 리스트든 해쉬 맵이든 서버에는 배열적인 요소 가지고 있다가 배열적인 요소에 소켓 담아둠. 이 소켓 정보는 1,2번 이런식으로 저장해야한다(당연, 1:1일때는 필요 없겠지만.)
3. Socket을 이용한 Multi-Chatting 만들기
HashMap으로 키값으로 아이디나 이름을 넣고 값으로 메시지를 보내준다. 소켓에 클라이언트가 메세지 받으면 정보 다 뿌려줘야(브로드캐스팅) 그래서 Output이라는 게 있어야 하고 소켓 정보에 아웃풋 스트림을 해시맵에 저장.
서버입장에선 응답하기 위한 출력스트림이 있으면 됨.
이 해시맵 안에 있는걸 반복문으로 모든 클라이언트 뿌려주는데 이게 브로드 캐스팅이고 이게 해시맵이다.
마지막에 클라이언트가 quit을 누르게 되면 소켓이 close됨. 그래서 해시맵이 없으면 서버창으로 뿌려지게 하기.
박이라는 사람이 입장하면 해시 맵에 키에는 박, 값은 아웃풋 스트림.
리도 마찬가지로 해시맵에 들어감.
서버입장에서는 소켓 접속하면 스레드 만듬.
해시맵의 정보 읽어와서 반복문 써서 이 모든 해시 맵을 브로드캐스팅한다.
클라이언트는 sender로 보낼 때는 소켓정보 있어야 됨.
이 서버에 전송하기 위해서 작업. 리시버는 수신해서 도스창에 출력함.
이것도 소켓이 있어야 함. 이것도 소켓이 있어야 수신한다.
서버 먼저 구동 해시 맵 객체 만듬
클라이언트에 해시 맵 담고 싱크로나이즈해시맵은 브로드캐스팅 할때 동기화가 안되서 다른 클래스 맞춰주기 위해 싱크로나이즈 맞춰줌.
서버에는 HashMap이 있는데 키에는 박, 값에는 output이 들어감
서버입장에선 입장하면 스레드 만듬. 이 해쉬맵 정보를 읽어와서 열거형으로 반복문 써서 이 모든 해쉬맵을 브로드캐스팅(방송)해서 쫙 뿌림.
모든 클라이언트한테 다 뿌려주게 된다.
클라이언트는 센더를 통해 보낸다. 그리고 소켓쪽에 네임을 통해 보내고 리시버는 받을 떄 필요. 서버에서 요청을 받아오면 출력하게 된다.
서버에서 서버가 스타트 되고 서버가 하는 일은 클라이언트 접속 계속 기다림. accept로 기다리고 소켓이 만들어지는데 서버에서 만들어졌지만 ip주소라던가 포트 번호를 가져옴.
서버는 클라이언트에서 이름과 소켓을 만듬. 이 소켓정보를 통해서클라이언트에서 정보 날아오면 쓰레드 실행해서 리시버가 받고 런 하게 됨.
이 스레드는 생성자에서 소켓 받아서 소켓정보로 입출력 스트림 만듬.
그리고 입출력 io 만들고 run 메서드 만들어서 실
근데 해시맵에 박이라는 객체(이미 있는 객체가 있으면 입장하면 안됨)
소켓을 생성 했다고 해도 커넥션을 끊어버린다.
같은 사용자가 없으면 sendtoall 로 모든 접속된 클라이언트에게 해시 맵에서 모든 키값들을 가지고 와서 그 키에 해당하는 모든 접속되어있는 키값에 아웃풋 스트림 가지고 와서 클라이언트에게 뿌려줌.
그 사람을 clientput하면 아웃풋 스트림 추가
while문 통해서 입력.
달라붙어있는 클라이언트가 리드하고 전체에 브로드캐스팅함.
여기까지가 서버가 주요 하는 일
클라이언트는 소켓 만들고 키보드로부터 입력 받아서 소켓으로 입력 받고 소켓 정보를 스레드로 스타트함.
보내는 스레드는 서버 있어야 보냄.
보내는 스레드는 아웃풋 스트림, 받는 스레드는 인풋으로 받기만 하면 됨.
와일문으로 입력 계속함. 그걸 read.UTF로 받아서 출력하면 됨.
클라이언트는 두개 쓰레드 만들어서 보내는 스레드, 받는 스레드 만들면 된다.