Daily coding
Thread 사용한 소켓 프로그래밍 예제 - server 본문
Thread 사용한 소켓 프로그래밍 예제
< Server >
1. main 클래스
- 필요한 변수
1) 문지기 소켓 : ServerSocket
- 특정 port 번호를 설정하고, 해당 포트(서버)에 접속하는 클라이언트를 확인한다.
- accept( ) : 문지기 소켓의 listen과 binding 기능을 한꺼번에 처리해주고 클라이언트가 있는 지 확인한다
접속하는 클라이언트가 생기면 Socket 타입의 담당자 소켓을 생성한다.
생성된 담당자 소켓은 Arraylist에 저장하여 관리하도록 한다.
- 클라이언트가 들어오면 클라이언트로부터 오는 메세지를 받기 위한 스레드를 생성하고
while문이 실행되어 새로운 클라이언트를 대기한다.
2) ServerThread 초기화
- 서버에 클라이언트가 들어오면 ServerThread가 생성되고, 메세지를 대기한다.
package day17.Lecture01_thread.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Server_mainClass {
public static void main(String[] args) throws IOException {
// 서버의 메인 화면
Socket clientSocket = null;
// Client Socket, 담당자 소켓 , 접속하는 클라이언트의 정보를 받아서 가지고 있음
// 포트넘버 9000을 지키고 있는 문지기소켓 serSocket
ServerSocket serSocket = new ServerSocket(9000);
// 접속하는 클라이언트의 정보를 담고 있는 리스트 만들기
List<Socket> list = new ArrayList<Socket>();
// while 루프가 시작되는 부분 :
while(true) { // 이렇게 하면 계속대화를 할 수 있음
System.out.println("접속대기중...");
// 접속 확인 ...
clientSocket = serSocket.accept();
// 클라이언트와 연결이 되면 밑으로 넘어간다.
// 확인 작업
System.out.println("client IP : " + clientSocket.getInetAddress()
+ " Port: " + clientSocket.getPort());
// 접속한 클라이언트의 정보를 list에 담아준다.
list.add(clientSocket);
// 서버의 send와 receive는 스레드로 만들어 주어야 한다.
// 1. receive 스레드
// 스레드는 반드시 start 메소드를 실행해줘야 한다.
new ServerThread(clientSocket, list).start();
// 다른 클라이언트와 대화하기 위해서는 다른 클라이언트의 소켓 주소를 알아야 한다.
// 리스트에 담긴 클라이언트의 정보를 확인한다.
}
}
}
2) ServerThread
- 생성자 : 서버 메인 클래스에서 클라이언트 담당자 소켓과 담당자소켓이 담긴 Arraylist를 파라미터로 받아온다.
- run() : 스레드가 시작되면 (start) 반드시 실행되는 메소드를 오버라이딩한다.
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- 클라이언트로부터 전달받은 데이터를 담당자 소켓으로부터 꺼내온다 ( getInputStream)
- BufferedReader를 객체를 생성해서 받아온 데이터를 읽을 준비를 한다.
- readLine( ) 메소드를 통해서 데이터를 읽고 String 변수에 담아준다.
* 클라이언트가 보낸 메세지를 다시 클라이언트에게 보내기
- 클라이언트로 부터 받은 메세지를 다른 클라이언트에게 보내준다 ( 채팅창에 텍스트를 뿌리는 것과 같은 행위 )
- 데이터를 보낸 클라이언트도 메세지를 받거나 받지 않도록 설정할 수 있다.
< 코드 분석 >
PrintWriter writer = new PrintWriter(sock.getOutputStream());
- 담당자 소켓이 외부 데이터를 받아들이는 getOutputStream를 담은 문자열 데이터를 쓸 수 있는 PrintWriter 클래스 객체를 생성
- 객체 writer를 통해 문자열을 담당자 소켓으로 보낼 수 있다.
- 데이터를 보내기 위해서는 반드시 flush()를 걸어 데이터를 보내주어야 한다 ( 아니면 오류 발생 )
// 본인은 제외하고 싶으면 if문으로 걸어준다.
if(socket != sock) { <---- 어레이 리스트를 담은 foreach 문을 돌릴 때, 자기 자신은 제외한다. (자세한 코드는 아래)
PrintWriter writer = new PrintWriter(sock.getOutputStream());
writer.println(str); // 실질적으로 전송이 되는 문자열
writer.flush(); // 끝맺음, 반드시 해줘야함
}
package day17.Lecture01_thread.server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.List;
public class ServerThread extends Thread {
// 서버에서 받아올 소켓 필드
Socket socket;
List<Socket> list;
// 생성자에 접속한 클라이언트 담당자 소켓과,
// 접속한 모든 클라이언트 정보가 담긴 리스트를 외부로부터 가지고 온다.
public ServerThread(Socket socket,List<Socket> list) {
this.socket = socket;
// 다른 클라이언트에 메세지를 보낼 수 있도록
// 서버에 접속한 클라이언트 정보를 담고 있는 리스트를 넘겨받는다.
this.list = list;
}
// 스레드 작동 시 돌아갈 메소드 오버라이딩
@Override
public void run() {
super.run();
try {
// 쓰레드를 계속 돌리기 위해 무한루프
while (true) {
// 1. receive
// while을 통해 담당자소켓이 정보를 계속 받는다.
BufferedReader reader =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = reader.readLine();
System.out.println("서버로부터 받은 메세지 : " + str);
// 2. send
for (Socket sock : list) {
// // 본인도 보내고 싶으면 아래의 코드로
// PrintWriter writer = new PrintWriter(sock.getOutputStream());
// writer.println(str); // 실질적으로 전송이 되는 문자열
// writer.flush(); // 끝맺음, 반드시 해줘야함
// 본인은 제외하고 싶으면 if문으로 걸어준다.
if(socket != sock) {
PrintWriter writer = new PrintWriter(sock.getOutputStream());
writer.println(str); // 실질적으로 전송이 되는 문자열
writer.flush(); // 끝맺음, 반드시 해줘야함
}
}
// CPU 부하가 안걸리고 제대로 돌아가기 위해서는 sleep() 걸어주어야 함
Thread.sleep(300); // = 30 프레임, 30번 갱신(가장 좋음)
}
} catch (Exception e) {
// 클라이언트가 접속을 종료하면 발생함
System.out.println("연결이 끊긴 IP: " + socket.getInetAddress());
list.remove(socket);
// 남은 클라이언트 확인
for (Socket s : list) {
System.out.println("접속되어있는 IP: " + s.getInetAddress()+" Port : " + s.getPort());
}
try {
socket.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
'Language > Java_basic' 카테고리의 다른 글
Thread 사용한 소켓 프로그래밍 예제 - client (0) | 2019.12.11 |
---|---|
Java Basic : day 17 - Thread의 개념과 예제 (0) | 2019.12.11 |
Java Basic : day 16 - 서버 / 클라이언트 연결하기 (0) | 2019.12.09 |
Java Basic : day 16 - 네트워크 TCP / UDP (0) | 2019.12.09 |
Java Basic : day 15 - AWT & SWING : Example - 선수 데이터 관리 프로그램 만들기 (0) | 2019.12.08 |