일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 부스트코스
- 이진법
- SW
- CS 기초
- 면접을 위한 CS 전공지식 노트
- ssafy
- WebProgramming
- Compute Science
- 관계형 데이터베이스
- CS 기초지식
- edwith
- 데이터베이스 모델링
- 알고리즘
- w3schools
- 예외처리
- java
- 모두를 위한 컴퓨터 과학
- SSAFY 9기
- til
- exception
- CS50
- 모두를 위한 컴퓨터 과학(CS50)
- CS기초지식
- 객체지향
- Computer Science
- ERD
- 상속
- Java Programming
- 기초프로그래밍
- 삼성청년SW아카데미
- Today
- Total
Joslynn의 하루
대용량 웹서비스를 위한 MSA Full-Stack 개발자 양성 과정 -19일차 노트 필기_멀티스레드(inturrpt method, Daemon Thread), 네트워크, 멀티채팅구현_220817 본문
대용량 웹서비스를 위한 MSA Full-Stack 개발자 양성 과정 -19일차 노트 필기_멀티스레드(inturrpt method, Daemon Thread), 네트워크, 멀티채팅구현_220817
Joslynn 2022. 8. 18. 22:13멀티스레드
Inturrupt() 메소드
: 스레드가 일시 정지 상태에 있을 때 InterruptedException 예외를 발생시키는 역할
예제)
: thread 시작 후, 0.1초 일시 중지(sleep 메소드) 이후, InterruptedException이 발생하여 thread를 멈추도록 interrupt() 메소드를 호출
package ex0817.thread;
public class IterruptedExam {
public static void main(String[] args) {
System.out.println("****메인 시작합니다.*****");
Thread th = new Thread(()->{
while (true) {
System.out.println("Thread 재미있다...");
// 무한 루프를 일시중지 시켜야 현재 스레드를 중지시킬 수 있음;
if(Thread.interrupted()) break;
}
});
th.start();
try {
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
//interrupt()는 스레드가 잠시 일시중지 상태가 되어야만 현재 스레드를 중지시킬 수 있다.
th.interrupt();
System.out.println("****메인 종료합니다.*****");
}
}
Daemon Thread
: 일반 스레드(Normal Thread)의 작업을 돕는 보조적 역할을 담당하는 스레드
:낮은 우선순위low priority를 가지고 있으며, 메인스레드가 종료가 되면 데몬 스레드도 강제 종료가 된다.
예제)
package ex0817.thread;
public class DaemonThreadExam {
public static void main(String[] args) {
System.out.println("***메인 시작합니다.***");
Runnable r = () ->{
while(true) {
System.out.println("나는 데몬 스레드입니다.");
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
};
Thread th = new Thread(r);
th.setDaemon(true); // 데몬 스레드 - 메인 스레드가 종료되면 함께 종료
th.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("***메인 종료합니다.***");
}
}
Network
: import java.net.*;
*용어
- ip: 숫자 체계, 컴퓨터 네트워크 상에서 각 장치들의 고유 번호
- Domain: 문자 체계, ip를 조금 더 식별하기 쉽게
- port: 프로세스
- URL, URI
ex) http://www.daum.net ----> http://www.daum.net:80/index.html
통신 규약:// IP 주소 or 도메인 주소 : 포트 주소/파일 이름(자원이름)
http의 기본 port 번호: 80 (기재하지 않아도 자동으로 열림)
네트워크를 하는 방법
1) UDP 방법
: 비연결성 통신 방법 ex) 우체국
: 일정량의 패킷(data)을 모아두었다가 한번에 전송하는 형태
: 네트워크 부담은 낮지만 신뢰성 떨어짐(바로 전송되지 않고 중간에 데이터 손실될 수 있음)
: DatagramPacket, DatagramSocket
2) TCP 방법
: 연결성 통신방법 ex) email
: 데이터를 보내는 동시에 바로 전송되어진다.
: 신뢰성은 높지만 네트워크 부담은 크다.
: ServerSocket, Socket
Server
: 클라이언트에게 여러 가지 서비스를 제공하는 것
SeverSocket 객체 = new SeverSocket(port 번호);
ServerSocket(객체)
: 서버 프로그램에서만 사용하는 소켓으로, 클라이언트로부터 연결 요청이 오기를 기다렸다가 연결 요청이 들어오면 클라이언트와 연결을 맺고 다른 소켓을 만드는 역할
: .accept() 메소드 : client 접속 대기, client의 요청을 받으면 Socket(접속한 client) 객체를 리턴
Socket(객체)
: 소켓은 두 프로그램이 네트워크를 통해 서로 통신을 수행할 수 있도록 양쪽에 생성되는 링크의 단자
: 두 소켓이 연결되면 서로 다른 프로세스끼리 데이터를 전달할 수 있다.
: client와 sever 모두 socket을 가진다 == 둘 간에 연결되어 있음
: .getInputStream() 메소드 : InputStream 리턴(바이트 단위 읽기), client가 보내온 byte를 읽기
== Buffered InputStream 사용 등은 IO에서 담당
: .getOutputStream() 메소드: OutputStream 리턴(바이트 단위 쓰기), 연결된 client에게 데이터를 전송하기 위함
class Server{
ServerSocket s = new ServerSocket(8000);
while(true){
Socket sk = s.accept();
InputStream i = sk.getInputStream();
OutputStream o = sk.getOutputStream();
}
sk.close();
}
Client
Socket sk = new Socket(String ip(domain or PC의 ip), port);
---> 문제가 있을 경우 Exception 발생, 없을 경우 server의 accept() 메소드가 받아줌
sk. getInputStream() : 서버가 보내온 데이터를 읽기
sk.getOutputStream(): 서버에게 데이터를 보낸다.
sk.close(): 소켓을 다 쓰고 나면 close하는 역할
데이터 통신에 유용한 IO
1. 읽기
byte 단위로 읽고 문자 단위로 변환
: InputStreamReader
Reader -> Buffered를 이용한 속도 향상 권장
: BufferedReader
2. 쓰기
byte 단위로 받아서 -> 문자 단위로 변환
: OutputStreamWriter
Writer -> Buffered를 이용한 속도 향상 권장
: BufferedWriter
**PrintWriter
: 각 타입별로 데이터를 전송할 수 있는 메소드 제공
: 타입별로 데이터 전송 시에는 BufferedWriter보다 이용하기 용이함
예제)
1대 1 채팅 구조
예제)
멀티 채팅 구조
서버
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerChatGUI {
Socket socket;
String userIP;
List<ClientSocketThread> list = new ArrayList<ServerChatGUI.ClientSocketThread>();
public ServerChatGUI(){
try (ServerSocket server = new ServerSocket(8000)) {
while(true) {
System.out.println("CLIENT 접속 대기 중");
socket = server.accept();
userIP = socket.getInetAddress().toString();
System.out.println(userIP+"님이 접속되셨습니다.");
// 접속된 client를 Thread로 만들어서 저장소(List)에 저장한다.
ClientSocketThread th = new ClientSocketThread();
list.add(th);
th.start();
System.out.println("현재 접속 인원: "+list.size()+" 명");
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ServerChatGUI();
}
/**
* List에 저장된 ClientSocketThread를 꺼내서 모든 User에게 메세지를 전송하는 기능
* */
public void sendMessage(String message) {
for (ClientSocketThread th : list) {
th.pw.println(message);
}
}
/** InnerClass
* */
class ClientSocketThread extends Thread{
// 외부에서 접근을 허용하기 위해
PrintWriter pw;
BufferedReader br;
String nikName;
@Override
public void run() {
try {
// 읽기
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 쓰기
pw = new PrintWriter(socket.getOutputStream(), true); // autoFlush;
// 대화명 읽기
nikName = br.readLine();
// 모든 유저에게 "nikName님이 입장하셨습니다" 메시지를 전송
sendMessage(nikName+"님이 입장하셨습니다.");
String inputData = null;
while ((inputData= br.readLine())!=null) {
// 접속된 모든 client에게 데이터를 전송
sendMessage("[ "+nikName+" ] "+inputData);
}
} catch (Exception e) {
//e.printStackTrace();
// 현재 스레드에 해당하는 Client의 socket이 닫힘;
// list에 제거
list.remove(this);
// 남아있는 모든 USER에게 알림
sendMessage("[ "+nikName+" ] 님이 퇴장하셨습니다.");
// 서버창에도 알린다.
System.out.println("[ "+nikName+" ] 님이 퇴장하셨습니다. 현재 접속 인원: "+list.size()+" 명");
}
}
}
}
클라이언트
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ClientChatGUI extends JFrame{
// client 화면용
JTextArea textArea = new JTextArea();
JScrollPane jsp = new JScrollPane(textArea); // 인수로 들어간 component 영역에 스크롤바가 생김
JTextField text = new JTextField();
// 통신용
Socket socket;
PrintWriter pw;
BufferedReader br;
public ClientChatGUI(){ // 생성자
super("채팅창");
Container con = super.getContentPane();
con.add(jsp, BorderLayout.CENTER);
con.add(text, BorderLayout.SOUTH);
// 옵션 설정
textArea.setBackground(Color.PINK);
textArea.setFocusable(false); // 커서가 가르키지 못함;
// 화면 조정
setSize(400,300);
setLocationRelativeTo(null);
setVisible(true);
//x를클릭하면 프로그램 종료
setDefaultCloseOperation(ClientChatGUI.EXIT_ON_CLOSE);
// 서버 접속
this.connectToServer();
// 서버가 보내주는 데이터를 받아서 textArea에 출력하는 스레드
Thread th = new Thread(()->{
//run 메소드
try {
String data = null;
while((data = br.readLine())!=null) {
textArea.append(data+"\n");
//스크롤이 마지막 글자가 있는 위치로 이동시키기
textArea.setCaretPosition(text.getText().length());
}
} catch (Exception e) {
e.printStackTrace();
}
});
th.setDaemon(true); // 메인 스레드가 종료되면 함께 종료
th.start();
// 생성자 마지막 - 이벤트 등록 (textField의 엔터)
text.addActionListener((e)->{ // ActionEvent 인수로 받음
//textField의 값을 읽어서 서버에 전송
String inputData = text.getText();
pw.println(inputData);
//textField의 값 지움
text.setText("");
});
}// 생성자 끝
/**채팅을 위한 서버에 접속 기능
* */
public void connectToServer() {
try {
socket = new Socket("127.0.0.1", 8000);
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream(), true);
// 대화명 입력창 - this(==JFrame), inputDialog가 끝날 때까지 JFrame에 접근 불가 && user's input 리턴
String name = JOptionPane.showInputDialog(this, "대화명을 입력해주세요.");
//서버에 대화명 전송
pw.println(name);
//JFrame 창 이름 변경
setTitle("[ "+name+" ]");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ClientChatGUI();
}
}