2021-09-30

0930 tomcat max thread 실험!

 

1. 톰캣 max thread를 1개로 제한하고 100개 클라이언트를 받도록 한경우.( 하나의 클라이언트 요청 약 2초) => 100초 이상걸렸음!! 당연하다. 하나의 톰캣스레드가 혼자 작업을 수행하고, 작업이 끝날때까지 블로킹이 일어난다. blocking이 일어나면 다른 스레드로 교체해줘야 되는데 교체할 스레드가 없다. ㅋㅋ



2. 100개 max thread 톰캣에게 약 2초걸리는 작업을 할당 -> 3초 조금 넘게 걸림. context 스위칭 하는 시간 이 걸려서?


3. Async한 서버로 만든경우:

2초 조금 넘게걸렸다!!!! (세상에) 똑같이 톰캣스레드는 1개인데!!! 대신 작업스레드가 늘어난다. 어떤기준인지는 몰겠으나. 이경우 8개의 워커스레드가 뒤에서 동작하였다. 아마 내가 지금 4코어 컴퓨터라서 4*2= 8 개 만든것인가??




요청을 1000개 로 늘렸더니. 서버는 작업 다 끝냈다고 하는데 클라이언트 쪽은 무한대기에 빠졌다?? 왜지?

2021-09-29

0929 CyclicBarrier 사용하기

 


1.CyclicBarrier 클래스

await()이 불린만큼 생성자안의 넘버가 한개씩 줄어들고.

넘버==0 이되면 메소드를 수행한다. 

2. 나의 경우

메인메서드에서 일단 한번 await() 걸어서. 얘 혼자 스택 못끝내게 만들어놓고.

100개의 스레드 다 만들어져서 await()이 총 101번 걸리면 그때 한꺼번에 호출!

그렇게 함으로써 total elapsed time을 구할 수 있도록 한다!


lock걸어서 동기화한다음에

await() 이 불릴때마다 카운트가 -1 씩 줄어들고

0이 되면 runnable 의 run()호출함을 확인할 수 있음. 


번외) AtomicInteger , AtomicLong클래스

Synchronized 키워드는 기본적으로 비관적 잠금이다. 

동기화 이슈는 확률적으로 매우 작게 일어나긴 하지만 , 일단 잠가놓고 본다.

그렇지만 Atomic~~클래스는 낙관적잠금을 한다.

일단 공유되어질수있고, 해당 공유되어진 값에 차이가 날경우 롤백?보완?잠금?하는 방식이라고한다. 따라서 성능면에서 더 좋다. 

아토믹하다, 원자적이라는 것은 더이상 쪼갤수없다는 것.

이를 테면 원자적 연산이란 = 더이상 쪼갤수없는 연산, 한번에 처리될 수 있는 연산을 의미한다. 

int a = 0은 원자적 연산이다.

하지만 a++ 은 원자적 연산이 아니다.

int a = 0 을 살펴보면

a 를 로드한다(4바이트) & 0을 로드한다(4바이트) & a에 0을 대입한다 => 컴퓨터가 원자적으로 처리할수있다.

하지만 a ++은어떨까?

a = a+ 1 이므로

더하는 과정에서 연산이 쪼개진다.(?) 

그리고 a가 int 가 아니라. long일경우에도! 8바이트가 되어서 연산이 쪼개진다고 함.

더 공부해야징~~


0929 톰캣 스레드 개수를 제한했을 경우

 

톰캣 max 스레드 개수를 10개로 제한


서버의 스레드가 10개로 제한되어 계속 돌려쓰기된다. 매우 느리게 된다!!



클라이언트 측에서는 스레드가 계속 만들어지는데. 서버측에서 이걸 못받아주니까 처리속도가 무지 느려진다! 

0929 inner class 재미있는 오류발생

 

해당 restController클래스에 static을 붙이지 않았을때 생기는 오류

Inner 클래스를 static 메인에서 참조하기 때문에 생긴다.

SpringbootRunner로 run()을 올리면. restController가 인스턴스로 뜨는 건가? 어떤식으로 참조하고 있는 거지. 

메인메서드 에서 static하게 클래스를 올려야 하는데

스태틱하지 않은 inner클래스가 있어서 에러.


해결방법 1) inner클래스를 바깥으로 빼낸다. public 키워드는 제외한다. 하나의 java파일안에 public 클래스는 단 하나밖에 있을수없으며 파일명과 동일해야 한다.


해결방법 2) static inner클래스로 만든다.

2021-09-28

0928 멀티스레드 테스트

 

약 1초 걸리는 thread를 10000개 만들어서 테스트.

톰캣의 max스레드 개수는 200개라고 알고있다.

확실히 200개까지 스레드가 만들어지고 그 이상은 안만들어진다. 계속 200개로 돌려쓰는 것을 알수있다. 


시간은 대략 3초 걸림. 생각보다 빠르네?!!

-----------------------------------
궁금해서 동기로 처리해봄 ㅎ

우선 클라이언트의 메인스레드가 sleep-working을 계속 반복하고 있음을 알수있다. io작업이 일어나는 동안의 blocking이 일어나는것이다.


서버 스레드의 경우 10개스레드로 돌린다. 
너무 못참겠어서 중간에 꺼버렸다. ㅎㅎ;;

2021-09-21

0921 head,tail, more,less

- head -숫자 [파일명]

위에서부터 몇줄 읽을것인지. 기본적으로는 10줄

- tail -숫자 [파일명]

아래에서부터 몇줄 읽을 것인지 출력. 기본적으로 마찬가지로 10줄

업데이트한 파일있을때 아래에 붙을것이니. tail쓰면 유용

- more, less

엔터를 누르면 한줄씩. 스페이스바를 누르면 한페이지 단위로 넘어간다. 문서양이 많을 때(cat으로는 너무 길어서 읽기힘든 파일) 을 읽을 때 유용.

- touch [파일명]

빈 파일을 만들때 사용. 이미 해당 파일명이 존재할 시 update시간을 해준다. 

0921 소켓 프로그래밍

 

알쏭달쏭...

서버: 인풋 아웃풋 스트림을 소켓으로부터 받아서 연다.

가지고 있는 해쉬맵(클라이언트 접속정보 저장) 에 모두에게 메시지를 보낸다.

클라이언트: 인풋으로 읽고 아웃풋으로 쓴다.

코드를 보면 ~~ 쉬운것같기도 하고~~~ 우아앙.

뭔가 확!! 풀리지가 . 않네~~ 




2021-09-18

0918 캐스팅 이해하기

 

부모 인스턴스를 자식 인스턴스로 강제 형변환 할시

컴파일 시에는 오류가 되지 않는다. 컴파일시에는 타입체크만 이루어지기 때문이다.

하지만 런타임시에는 오류가 발생한다. 

강제캐스팅(다운캐스팅) 한다는 것은 단순히 타입만 바꾸어주는 것이지 해당 인스턴스자체를 변환시키는 것이 아니기 때문이다.

따라서 이럴때에는 instance of를 이용하여 반드시 해당 인스턴스의 타입이 정말로 일치하는지를 검증해주어야 한다.


----


이런식으로 간단하게 인스턴스체크를 해볼수있다!!

0918 커맨드라인으로 String args받기

 



Scanner 클래스 대신에 커맨드라인으로 매개변수를 받고 출력하는 메서드!!
ㅋㅋ 뭔가 쫌 귀엽고 웃기다.

2021-09-16

0916 java7, java8

# 31장 java7에 추가된 것들에는?

1.Fork/Join 메서드

- recursive하게 호출하고 싶을때 사용

- RecursiveTask, RecursiveAction이 있음. return값 있느냐 없느냐의 차이.

- WorkStealing개념을 이용하여 효율적으로 일을 처리할 수 있다.

2. I/O관련

- Paths : 기존 File보다 좀더 다양한 메소드를 제공. 오라클에서도 File보다 제발 이쪽을 사용해달라고 권장하는 중. 

-WatchService : 해당 디렉토리를 감시하며, 옵션으로 enum클래스를 넘겨서 해당 디렉토리에 이벤트가 발생했을때 WatchKey의 내용을 확인할 수 있다.

# 32장 java8에 추가된 것들은?

- Optional : null처리를 효율적으로 하기 위하여 사용. 단 Optional로 감싸는 비용자체가 발생할 수 있음(객체가 무거워짐) 컬렉션일 경우 null을 반환하지 말고 빈 컬렉션을 반환하거나. null대신 exception을 던진다는 선택지도 생각해볼 수 있음. 

- 인터페이스의 default method : 그런데 예기치않게 우연히 default메서드로 구현해놓은 메서드 시그니처가 겹치면? 충돌난다. 

- 시간관련 : LocalDateTime등의 클래스가 추가됨. 스레드 안전하며 훨씬 깔끔한 메서드를 제공하니 이쪽을 애용하자. 

- StringJoiner : 문자열 깔끔하게 붙여줌. 파이썬의 join메서드랑 비슷한듯

# 33장 java8에 변경된 것들은?

- Functional Interface -> 람다식으로 간단하게 구현가능.

- 자바 자체적으로 제공하는 Functional Interface들이 있음. 굳이 Functioanl Interface 를 만들지 않고도 이 인터페이스들을 활용하면 쉽다. 단, 메서드 명을 좀더 명확하게 할 필요성이 있다면 새로 인터페이스 만드는 것도 생각해봄직함.

- stream api : 컬렉션을 stream 으로 만들어서 (생성- 중간연산 n번 - 종단연산) 쉽게 처리가능. 단 , 과도하게 사용하면 오히려 가독성이 떨어질 수 있으니 적절하게 for문을 섞는등 고려하자. 

- 메서드 참조: 특정 클래스 혹은 인스턴스변수의 메서드 참조 / 생성자 참조 등 할수있다.

2021-09-15

0915 java Socket , java7

 28장 다른 서버로 데이터를 보내려면 어떻게 하면 되나요?

#네트워크 프로그래밍

 - 어플리케이션 레이어의 HTTP, 텔넷, FTP통신등- 전부 TCP통신 위에서 이루어진다. 자바의 경우 소켓을 이용하여 tcp통신을 구현할 수 있다. 

#서버- 클라이언트간 소켓통신

- 서버: SocketServer 객체 생성하여 포트를 연다.

클라이언트로부터 데이터를 받을 Socket객체 열고 accept()하여 데이터를 받을 준비를 한다. 

socket객체로부터 인풋스트림열어서 while(true)걸어주면서 계속 데이터 받는다.

데이터가 더이상 없으면 close한다.


- 클라이언트: 데이터를 보낼 Socket객체를 생성하고, 호스트ip와 포트번호를 생성자에 넣어서 생성한다. TCP/IP통신에서는 포트번호/호스트주소/프로세스id로 식별하기 때문이다.

socket객체로부터 아웃풋스트림 열어서 데이터 전송한다.

전송이 완료되면 close를 때려준다.


#UDP통신

- TCP통신과 다르게 데이터를 그냥 통으로 보낸다. 쪼개서 보내지 않는다. 그래서 Datagram이라는 객체를 이용한다. 버퍼의 사이즈/ 데이터의 length를 지정한다. 데이터를 그냥뭉텅이로 통으로 보내기 때문에 - 버퍼의 사이즈 >= 데이터 length여야한다. 

비연결성 비신뢰성이기 때문에 데이터가 잘 안보내져도 책임지지 않는다. 설령 server쪽에서 포트를 안열고 있다고 하더라도 오류가 발생하지 않는다. 검사하지 않기 때문이다. 

일반적으로 UDP를 사용해서 프로그래밍하게 될 일은 별로 없다고 한다. (쓰더라도 tcp랑 섞어쓰게 될듯)


30장 java7에서 달라진 것들에는?

# 숫자표현

- 0을 앞에 붙이면 8진수, 0x를 앞에 붙이면 16진수, 0b를 앞에 붙이면 2진수

- _를 이용해서 큰 숫자 표현가능

# switch-case문에 String 사용가능

# 제네릭과 다이아몬드

- 타입체크에 유의한다

- 배열의 경우 컴파일시 타입이 남고 / 제네릭의 경우 컴파일시 타입이 남지않음

- 제네릭의 타입은 컴파일시 소거되고, Object타입으로 변환됨

#  예외처리

-try -catch-resouces문 이용하여 Closable이용한 객체의 경우 명시적으로 close()부르지 않아도 깔끔하게 자원반납가능

- |를 이용하여 다수의 예외를 한꺼번에 처리가능 

2021-09-12

0912 운영체제와 스레드

 1. 운영체제의 역할중 중요한 것 : process관리, 프로세스 스케쥴링 & 동기화 문제 해결.

2. 프로세스 스케쥴링을 위한 다양한 큐

1) 하드웨어-> 메모리 2) 메모리 -> cpu 3) 메모리 -> 하드웨어 (임시해제. 한동안 해당 프로세스가 쓰이지 않을때 꺼져!! 하고 돌려보냄)

2) > 3) > 1)순으로 자주 일어난다. 

3. 편의상 프로세스 스케쥴링이라고 말하고 있지만- 사실 현대의 운영체제는 그것보다 훨씬훨씬 똑똑하다. 스레드 스케쥴링을 한다. p1프로세스의 1번스레드 2번스레드 돌리다가 p2프로세스의 a번 b번 돌리다가 하는 식이다. 스레드 스케쥴링을 위해서 해당 스레드 정보를 운영체제의 pcb영역에 저장했다가 돌아오면 restore하는 식으로 계속 context switching을 한다. 

그래서 스레드를 무작정 많이 만들어도 안좋은게 , context switching을 해야하는 비용이 많이 들고, 아무리 경량 프로세스라고 하더라도 스레드를 만드는 비용 ( code영역, data영역 생성등..) 이 있기 때문에. 적정 스레드 수를 유지하는 것이 중요하다. 

4. 스케쥴링 기법 : FIFO, priority , SJF, 라운드로빈(time- slicing) , 다단계 피드백 큐, 다단계 큐 등

5. 선점형 스케쥴링 vs 비선점형 스케쥴링 : 선점형은 우선순위에 따라서 cpu점유를 뺏길수있고, 비선점은 한번 cpu점유에 들어가면 뺏기지 않음. 

6. 스레드 동기화생각해야 하는 이유?

자바나 c같은 하이랭귀지 언어에서는 사실상

balance += money;

이렇게 한줄로 끝나는데. 사실 이걸 어셈블리어로 변환하면

1) money 데이터를 메모리에서cpu 레지스터로 load하고->

2) balance 데이터를 메모리에서 cpu 레지스터로 load하고-> 

3) add 한다

라는 여러 과정이 함축되어있음 . 

그래서 저 1,2,3과정중에서 여의치 않게 context switching이 일어나면 - 비정상적인(의도치않았던) 결과를 받아보게 되는 것이다. 

0912 세마포어

 세마포어의 원리: permit하는 스레드수를 제한한다.

acquire()를 불렀을때 permits--해서 , 만약에 0이하로 내려가면 해당 스레드를 세마포어라는 감옥(큐) 에 담아둔다.

realease()를 불렀을때 permits++해서, 세마포어 감옥에 들어가 있던 스레드를 불러서 턴을 넘겨준다. 


세마포어는 자바 concurrunt 패키지에 내장되어있다. (내가 안만들어도 됨!! 꺄호~)
먼저 parent 스레드를 시작시키고 -> child 스레드를 시작시키기 때문에,
parent가 deposit하는동안 child스레드는 세마포어 감옥에 갇히게 된다. 
parent가 deposit을 100번끝내야 그다음 child턴이 되어서 account에서 withdraw를 할 수 있다. 
Account객체를 공유하기때문이다-

스레드의 공유영역 : 힙메모리!!




0912 리눅스 명령어 종류

 1. builtin-command : 내부 명령어. bash안에 들어있는 것

ex) pwd

2. 외부명령어

3. alias

alias d='date'

그럼 d했을때 date명령어친것과 같은 효과. 

4. keyword

if, while, for문과 같은 제어문을 keyword라고 한다.

5. function

6. type명령어를 통해 해당 명령어가 어떤 타입인지 알 수 있다.

7. compgen -k :키워드 명령어 종류

-b : 빌트인명령어종류 출력

-a : alias명령어 출력

alias -> keyword -> function -> built-in -> 외부명령어 순으로 먼저적용된다(만약에 충돌될경우)

8. 영구적으로 해당 명령어 사용하고 싶다? -> .bashrc에 저장해둔다. 

9. stat명령어로 파일및디렉토리의 상태를 확인할 수 있다. 

0912 리눅스 history

 1. root는 특별한 사용자. /etc밑의 모든 파일들 건드릴 수 있음. /root라는 집이 따로 있다. 반면 그외 사용자들은 /home밑의 자기집 안에서만 활동가능.

2. source 명령어 = . 명령어와 같음

로그인 다시한것과 같은 효과낸다. 주로 명령어 같은거 bashrc에 편집한후 사용하게됨


3. 명령어 혹은 변수 만든것을 로그인할때마다 계속 사용하고 싶다면? -> bashrc파일밑에 써둔다. 왜냐면 내가 로그인한후 이 파일을 자동적으로 읽기 때문이다.

4. $HISTSIZE : 히스토리 저장하는 사이즈. 디폴트값 1000. 즉 1000개 명령어를 저장한다. .bash_history에 저장한다. history -c하면 히스토리가 클리어되지만 .bash_history는 클리어되지 않는다. 만약에 어떤 유저가 몰~래 다른 서버에 들어와서 이것저것 하고 간다면?? 이 .bash_history파일안내용도 지워주어야 할것이다. 

0912 리눅스 전역변수, 전역명령

1.  /etc : 여러 설정파일들들어있다

2. /etc/profile : 모든 유저들에게 공통으로적용

3. 

~/.bash_profile

~/.bashrc : 홈유저에게만 적용되는 내용들. 내가 여기에 설정한 명령은 다른 유저가 사용불가능 (공유x)만약에 공유하고 싶으면 /etc어쩌구안에 넣어야함. 


4. 일반사용자는 자기 home디렉토리 밑에서만 활동가능. 나머지 영역에서는 권한 오류 에러 뜬다.

5. 실행파일( 명령파일) -> PATH설정을 하면. 내가 사용할수있는 명령어들이 어디에서 불러와지는지 알 수 있음.

실행파일(쉘스크립트) 만들고  -> PATH밑에있는 디렉토리안에 해당 실행파일 열어두면 -> 전역에서 해당 명령어 사용할 수 있다.

6. 그럼 그 PATH설정은 어디서 불러오는가?? -> 내 로그인시 실행되는 ~/.bashrc, ~/.bash_profile에 쓰여있다. 

7. export란? 전역변수화.내 쉘 말고 내 자식 쉘에서도 사용할 수 있게 하는 명령어. env환경에 들어가게된다. 환경변수가 된다. export하면 다른 쉘에서도 사용할 수 있도록 승격화 된다. 자식 쉘에서도 변수의 효력이 미친다. 

exit(혹은 logout)을 여러번 해주어야 함. bash쉘을 여러번 만들어서 깊숙하게 들어왓기 때문이다. 

만약에 함수를 export해서 전역에서 사용하고 싶다면 -f옵션을 붙이면 된다. 


8. 함수를 만들고- 해당 함수는 해당 폴더내에서만 부를 수 있다.

즉 ./ssss.sh 이런식으로 불러야 해당 쉘 스크립트를 실행할수있다.

해당 실행은 ~/디렉토리경로/해당파일 이렇게 실행하는 것과 같고

$HOME/디렉토리경로/해당파일 이렇게 실행하는 것과도 같다. 

그런데 전역에서 그냥 경로없이 사용하고 싶다?? $PATH 변수 밑에있는 bin디렉토리밑으로 복붙해준다! 그러면 - 그냥 명령어를 전역에서 사용할수있게된다. 

아니면 아예 실행파일이 든 폴더 자체를 $PATH에 추가한다는 방식도 있는데, 이건 보안상으로 별로 좋지않은 방법이라구 함. 


9. 명령어 전역에서 사용하기 -> $PATH이용

명령어 다른 쉘에서도 사용하기 -> export이용




0912 운영체제와 프로세스

 1. 운영체제의 역할 : 하드웨어 자원관리, 성능(performance) , 편리성, 보안

2. 여러 사용자가 하나의 컴퓨터를 이용하는 경우 - 대표적으로, 서버컴퓨터를 생각할 수 있다.

여러명의 유저가 수강신청을 하기위해 하나의 서버 컴퓨터를 이용한다.

이때 만약 어떤 유저가 마음대로 하드웨어 자원에 접근할 수 있다면?? 해당 컴퓨터를 못쓰게 만들수도 있고, 다른 유저의 데이터를 마음대로 훔쳐볼 수도 있게된다.

이러한 보안 문제관련, 운영체제는 하드웨어 자원을 유저가 직접관리하도록 하는것이아니라 운영체제에게 맡기도록 한다. 만약 유저가 이러한 룰을 위반하고 맘대로 스스로 건드리려고 하면- 해당 프로세스는 중지된다. 

대표적으로 io자원을 생각할 수 있다. 자바로 프로그래밍할때 우리는 직접 하드웨어 자원이 어디있는지 명시적으로 알고 사용하지 않는다. 실제로는 디스크의 어딘가에 물리적으로 저장되어 있을테지만 그 위치를 우리가 찾아서 사용할 필요가 없다. 그냥 이 위치의 이 이름 파일을 불러줘~~ 하고 형식만 맞추어서 (스트림이든 버퍼든 채널이든) 운영체제에게 넘기면, 운영체제가 그것을 처리해준다. 개발자의 영역이 아니기 때문에 Exception을 반드시 걸어야 하는것 같다(이건 나의 추측)

그래서 어떠한 프로세스가 컴퓨터 메인메모리에 올라와있을때, 이 프로세스는 계속해서 user mode 와 system mode를 왔다갔다하는 상태를 겪는다.


3. 프로세스와 프로그램?

프로그램은 단순히 하드웨어에 저장되어 있는 실행파일에 지나지 않다. 이것은 무덤속에 가만히 누워있는 것과 똑같다.

프로세스는 메인메모리에 올라와있는 프로그램, 즉 실행중인 - 살아있는 작업이다. job이라든지 task라든지 여러 단어가 존재하는데 같다고 생각해도 좋다.

하드웨어 속에서 죽어있는 프로그램이 - 메인메모리에 올라와서 프로세스가 된다.

4. 프로세스의 상태

프로세스는 여러 상태변화를 가진다. 무덤속에 있을때는 잠잠했던 세상이 별세상이 되고 온갖 소리와 변화를 경험한다.

NEW - READY - RUNNING - WAITING - TERMINATED

NEW는 말그대로 생성되어 초기화되는 단계이고, 메모리에 완전히 올라와서 초기화가 종료되면 그때부터 cpu에게 처리될 수 있는 READY상태가 된다. 

그리고 실제로 cpu에게 처리되고있는 상태를 RUNNING상태라고 한다. 

단 우리는 multiprogrmming컴퓨터를 이용하고 있기 때문에, io작업 등 cpu의 연산능력을 필요로 하지않는- 다른 하드웨어 부서를 이용해야 하는 작업이 요구될경우 자연스럽게 자리를 양보하며 waiting 상태로, 그리고나서 io를 끝내고 ready큐로 다시 들어와서 기다린다.

여기에 플러스, time sharing을 이용하고 있기 때문에 - running에서 - 할당된 시간이 종료되념 다시 ready큐로 들어온다.

결국 ready-running-waiting의 상태에서 빙빙빙 계속 돌다가, 프로세스가 종료되면 그제서야 terminated되며 메인메모리로부터 할당이 해제되는 것이다. 

2021-09-11

0911 가상머신에서 인터넷 접속하기

https://mainia.tistory.com/5609

<<완전 깔끔한 해결책!! 많은 도움이 되었습니다.



0911 운영체제의 이해

 1. 운영체제의 역할 : 하드웨어제어, 성능, 편리성

특히 하드웨어 제어역할 매우 중요. 운영체제는 마치 정부와 같다. 다양한 리소스(국토, 돈, 사람등등..) 을 제어하여, 야생마와 같은 컴퓨터를 관리하는 것이다. 

하드웨어 리소스의 종류 : cpu, 랜카드(네트워크 통신담당), 메인 메모리, 마우스, 키보드, 모니터, 등등 모든 물리적인 것들 포함한다. 컴퓨터안의 작은 장치들 모두모두!!

mount 와 umount같은 명령어가 왜 있는거지 생각했는데 - 내가 당연히 생각하고 있었던. 하드웨어와 하드웨어의 연결을 위한 아주 중요한 명령어였던 것이다!! (요새는. plug& play로 자동지원되니까.. 이런 생각 자체를 해본적이 없었다. )

정부는 다양한 부서가 있고, 부서별로 명령을 내려서 해당 자원이 효율적으로 사용될 수 있도록 사령탑. 운영체제도 이와 똑같다. 스스로 일을 하는 것은 아니고, 명령을 내리는 사령탑이고 지휘관이다. 그중 단연 톱으로 중요한 부서는 processor를 제어하는 부서이다. 

컴퓨터를 구성하고 있는 다양한 요소 중 cpu는 연산을 담당하는데 , 이 연산을 위해서는 메모리 공간 (연산결과를 저장) & processor가 필요하다. 이것을 운영체제가 알아서 해준다. 운영체제가 없었다면 우리는 프로그램을 실행하기 위해 일일이 load하고 제어하는 일을 해야했을 것이다..

2. 멀티프로세싱

여러개의 작업을 실행할 수 있다. 단일cpu 라고 가정했을때. cpu는 연산만 담당하기 때문에 출력을 요청하면- 그동안 idle한 상태가 된다. 이것은 매우비싼 자원인 컴퓨터를 이용하는 입장에서. 매우 불만인 것이다. 쉼없이 일해라 cpu!!이를 위해서, - 아 그럼, 메모리에 여러개 프로세스를 올려두고, io작업이 일어나면 다른 프로세스를 바로 돌릴수있게 하자. 하는 식으로 디자인하게 되었다.

이것때문에 고민해야 할 것들이 많아졌다. -> 메모리의 어디에 해당 프로세스를 저장할 것인가? 하는 장소문제. 프로세스들을 어떤 순서로 돌릴것인가? 하는 스케줄링 시간문제. 

3. time-sharing 시분할.

엄청나게 짧은 시간동안 멀티프로세싱을 돌리면, 너무 빨라서 마치 동시에 여러 작업이 수행되는 것처럼 느껴진다. 이를통해, interactive한 컴퓨터를 구현할 수 있게 되었다. 매우매우슬로우모션으로 본다면, 사실은 한번에 한개의 작업만 처리하고 있다. 하지만 너무너무 빨라서, 우리는 마치 컴퓨터가 바로바로 나의 요청에 응답해주는 것처럼 느낀다.

4. 인터럽트 기반 

interrupt란 무엇인가? 이것은 마치 운영체제에게 야~!! 하고 말거는 것이다. 지금 하는 일을 중단하고 어떠한 루틴을 수행하라! 라고 말하는 것이다. 운영체제는 ROM에서 부팅되어 RAM에 상주하고 있다. 그리고 어떠한 이벤트를 통해 interrupt가 발생하면, 운영체제는 해당 이벤트에 묶인 루틴을 수행한다. 

이 인터럽트에는 하드웨어기반 인터럽트와 소프트웨어 기반 인터럽트가 있다. 하드웨어 기반은 쉽게생각하면 마우스 움직이기. 사용자가 마우스를 움직이는 이벤트- 인터럽트가 발생했고, 운영체제는 user mode에서 kernel mode로 들어가서 , 해당 인터럽트에 해당하는 루틴을 수행한다(즉, 마우스를 움직인 것을 모니터 화면으로 보여주는 루틴 . 이것을 위해서는 모니터 하드웨어의 협력을 명령하게 될 것이다.) 

2021-09-09

0909 HTTP통신

 1. HTTP는 무상태 프로토콜이다.

이와 반대로, FTP는 상태유지 프로토콜이다.

팀 버너스리 박사가 HTTP를 발명하기 전에, FTP는 이미 널리 사용되고 있었다. 그럼 왜 굳이 FTP를 사용하지 않고 HTTP프로토콜을 만든걸까?

그 이유는 훨씬 가볍고 편리하니까!! 이다. FTP의 경우 계속해서 상태를 유지하기 때문에 - 데이터의 오버헤드가 너무 크고, 인증을 받아야 하기때문에 접속을 위해서는 서버 관리자에게 요청해서 권한을 받아야 한다. 

반면 HTTP는 상태유지를 하지 않기때문에 훨씬 빠르고 통신절차가 간편하다.

2. 무상태 프로토콜의 한계점을 극복하기 위한 쿠키와 세션

쿠키: 간편하지만 보안의 문제가 있다. 그냥 탈취하면 그만이기 땜에.. 그리고 용량의 한계도 있다. 

그래서 세션을 이용한다. 사용자가 접속하면 sessionID가 부여되는데, 이 세션ID를 쿠키에 담아서 사용자에게 전달한다. 그러면 사용자가 다시 접속했을때 쿠키가 존재하는지 안하는지 확인하고, 존재할 경우 까봐서 해당 sessionID가 서버의 세션정보에 저장되어 있는지 확인한다. 이렇게 하여 무상태프로토콜을 쓰면서도 각각의 페이지의 연결성을 유지할수 있도록 context를 만들어준다. 

이를 테면 장바구니 구현같은 것도 세션쿠키로 할 수 있다. 해당 sessionID의 테이블 정보에 장바구니 품목을 함께 저장하는 것이다. ( 서버 오버헤드가 크다는 문제점은 있겠지만) 그렇게 함으로써 사용자가 페이지를 나갔다가 돌아와도 장바구니 안에 담았던 품목들이 유지된다. 

but 세션을 끊으면 당연히 해당 내용은 날라간다. 다른 브라우저로 접속한다던지, 아니면 로그아웃 한다던지. 

2021-09-08

0908 리눅스 명령어 : cat , tac

 cat  : 파일 내용을 출력해줌

-n:번호 붙여서 출력 ( number)

-b:번호 붙여서 출력하되 공백에는 번호 붙이지 않음


tac : 거꾸로 출력해줌


> : 해당 내용을 옆으로 재지향(?) . 만약 이미 존재하는 파일일 경우 덮어쓰기 한다

>> : 뒤 꼬랑지에 해당 내용을 append해준다. 

echo 234 > test.txt

cal > a1

hostname >> a1

하는 식으로 쓸수있음

0908 파일 입출력

1. getAbsolutePath() / getCanonicalPath() 차이점:

getCanonicalPath() 는 해당 파일의 경로까지에서 ..을 제거하고 이쁜 절대경로만 출력해줌

2. FileFilter 클래스를 implements함으로써 원하는 파일만 걸러낼수 있다. ( 해당 이름을 포함하고 있는 파일만, 해당 형식의 파일만 등등. ) 

3. 파일입출력

1) InputStream -> InputStreamReader -> BufferedReader

: 1바이트씩 읽는다 -> 여러 바이트를 읽는다 -> 문자열(String)으로 읽는다. 

2) close()를 할때는 순서를 꼭 맞추어, 마지막에 연 객체를 가장 먼저 닫아야 한다. 그렇지 않으면 의존하고 있는 객체 순서가 안 맞아서 고아객체가 생길 수 있다.

3) Stream은 강물. 데이터의 흐름. 강물은 한쪽 방향으로만 흐른다. 거스를 수 없다. 즉 데이터의 흐름이 일방적이고, 양쪽으로 동시에 읽고쓸수없다. 따라서 InputStream과 OutputStream이 각각 따로 존재한다. 

4) System.in 은 InputStream 타입의 정적 필드 변수이다. 따라서 키보드 입력을 받을 때 흔히

Scanner(System.in)했던것은 - Scanner가 생성자 매개변수로 InputStream 타입을 받기 때문이다. 

5) InputStream은 1바이트씩 읽는다. 만약에 int를 넘길경우 2바이트이기 때문에 read()를 부르면 1바이트 읽고 나머지 1바이트는 stream안에 걍 남아있다 ㅋㅋㅋ 그럼 byte[]를 넘기면 어떻습니까? -> 그러나 한글은 char로 변환해도 깨진다. 아스키 코드값에 대응되지 않기 때문이다...

6) Scanner와 BufferedReader는 각기 장단점이 있다.  BufferedReader는 기본적으로 String타입( 혹은CharSequence 타입. 거기서 거기다.) 만 받는다. 공백이나 엔터도 그냥 다 String으로 퉁친다. 문자열을 따로 파싱하지 않기 때문에 속도가 굉장히 빠르다 (스택오버플로우에 따르면 Scanner의 약 6배) 

반면 Scanner는 nextInt nextLong등 .. 다양한 타입을 지원하며 자동으로 파싱해주니까 편리하다. 하지만 그만큼 내부적으로 복잡한 정규식검사를 거치기 때문에 속도가 훨씬 느리다. 동기화도 지원하지 않는다. 그리고 엔터나 공백을 BufferedReader와 다르게 처리하기 때문에 이로인한 부정확한 출력결과가 있을 수 있음. 사용에 주의한다. 

2021-09-07

0906 get, post, 퍼센트 인코딩

 1. get

입력한 매개변수값이 URI에 쿼리스트링으로 그대로 노출된다.

보안에 약할 수 있다.

부작용이 없다 = 언제나 같은 값을 보장한다. (정적)

내가 보낸 값이 그래도 URI에 저장되기 때문에 다른사람에게 그대로 페이지를 전달하기 용이하다.

글자수 제한이 있다(아마 255자 정도)


2. post

입력한 매개변수가 노출되지 않고body에 들어감.

글자수 제한이 없다.

get보다 보안에 강하다( 매개변수 노출x)

부작용이 있다 = 내가 보낸 결과가 항상 같은 페이지를 돌려주지는 않을 것이다. 


3. 퍼센트 인코딩

한글의 경우 어떻게 쿼리스트링으로 날라가는 것인가?

퍼센트인코딩( 앞글자에 %가 들어가는 식으로 구분되기 때문에 그렇게들 부른다) 을 브라우저가 처리하여, 한글또한 읽힐수있도록 인코딩-디코딩 처리를해준다. 그래서 영어권의 언어가 아니어도 값을 전달할 수 있다. 


4. UTF-8 

원래는 아스키 값 사용 - but. 한글, 중국어 일본어 등등.. 아스키 코드(1바이트)로는 턱없이 표현불가능한 문자들이 있음

그래서 유니코드 사용 - 불변 크기. 무조건 4바이트로 통일함. 영어같은경우 1바이트면 표현할 수 있는데 얘는 무조건 다 4바이트로 처리함. 비효율적.

그래서 UTF-8이 등장했다. 언어별로 가변적 크기를 할당하여 효율적으로 처리한다. 바이트의 앞자리에 어떤 숫자가 오는가로 바이트 크기를 계산하고(1바이트줄지 2바이트 줄지 등등) 크기 할당함. 

2021-09-06

0906 리눅스 명령어 : ls , ps, kill, killall

 1. ls 디렉토리 내의 파일 및 폴더 listing해준다

ls -a : 상세하게 보여줌. 숨겨진 디렉토리까지 all

ls -l : long 하게 보여줌

ls -r : 하위 디렉토리 까지 전부 보여줌 recursive

2. ps 프로세스 보여줌

ps -e : every 모든 프로세스 표시

ps -f : full format으로 표시

ps -p [PID] 해당 pid표시

3. kill [PID] 혹은 %[jobID]

kill -l 으로 kill 시그널의 종류 list 볼수있다

kill -15 : 가능한 정상적으로 종료 . 터미널에게 시그널을 보낸다. 터미널은 상황에 따라 시그널을 무시하거나 지연할 수 있음

kill -1 : 데몬의 경우 종료후 restart . 리프레시하는 효과

kill -9 : 당장 종료하라! dirty shutdown of application.

kill -20 : 잠깐 stop

kill -18 : continue. stop되었던 것을 재실행 시킴

4. killall : PID가 아니라 프로세스 이름으로 종료시킴

이를테면 killall -9 httpd 이면 httpd사용중인 프로세스 전부 종료됨

2021-09-05

0905 웹을 지탱하는 기술

 1. 웹 뒷받침하는 기술

1) 서버 & 클라이언트 : 자원을 가지고 있는 쪽을 서버라고 부른다

2) 자원 요청 어떻게 하는가? : 자원을 식별해주는 주소 URI를 부른다.

2-2) URI의 구성 : sheme(방법. http 인지 ssh인지 그런것들) / 호스트명 ( 서버 컴퓨터의 ip주소) / 자원의 경로 

3) HTTP /1.1 : 서로다른 컴퓨터간에 통신을 하고 정보를 주고받기 위한 규약


2 . 동적컨텐츠와 정적컨텐츠

1) 동적컨텐츠를 생성해주는 기술 : CGI -> 요청시마다 프로세스를 새로 띄우기 때문에 효율성 매우 떨어짐

2) Servlet & JSP : 일단 프로세스 띄우고( 웹 컨테이너) 그 안에서 servlet이 request를 처리하기 때문에 효율 높다

3) 프레임워크의 필요성 : 비슷한 틀 만들어서 jsp servlet작업하는데 이부분을 프레임워크화해서 개발효율성을 높이자!


3. request header와 response헤더

통신규약(HTTP)에 정해진 내용들이 담겨있다.

이를테면 request header에는 어떤 method로, 어떤 uri에, 어떤 통신규약(HTTP 1.1) 으로요청할 것인지 의 내용이있다.

그외에도 accept라는 필드:내용을 살펴보면 수신할수있는 컨텐츠 타입을 지정할 수 있다. 나는 text/plain만 받을거야! 라고 설정하면. 그외의 요청은 수신할 필요가 없으므로 훨씬 효율적으로 요청을 처리할 수 있다.

response헤더의 경우 contents도 담아야 하기 때문에 훨씬 길다.

한번의 요청 - 한번의 자원으로 이루어진다.사진이 많이 포함되어있는 요청이라면 그만큼의 요청 수가 날라간다. 


4. 사설 ip와 글로벌 ip 

ip주소 고갈문제를 해결하기 위해 등장하였다. 일정범위 이내에서는 사설ip만 사용함으로써 ip를 효율적으로 사용할수있게 되었다. 그래서 ip추적이라는 개념이 - 거의 불가능한게, 어짜피 밖에서 보이는 내 아이피는 글로벌 ip이다. 글로벌 ip는 계속바뀌기때문에 일개인이 이걸 바탕으로 주소를 알아내기란 불가능하다고 할 수 있다. 다만 글로벌 ip는 해당 주변 ISP가 할당하는 것이므로, 그 근처이겠구나(?) 정도로까지는 알 수 있을지도..


5. 호스트명(ip)어떻게 알아내는가 ?

DNS가 ip를 인간이 기억하기 쉬운 영문주소로 변환해준다.


6. 포트번호

통신을 위해서는 URI뿐만아니라 포트번호도 필요하다. ip주소만으로는 해당 호스트 컴퓨터의 어떤 어플리케이션을 이용할것인지 몰르기때문이다. 카카오톡으로 보냈는데 네이트온으로 오는 일은 없지 않은가. 일반적으로 웹의 경우 많이 사용되기 때문에 보통 80번을 사용한다. well-known-port라고 한다. 그래서 웹 애플리케이션을 이용할때 우리는 포트번호를 굳이 붙이지 않아도 되는것이다. 

0904 아파치 카프카 실습 준비

 1. 아마존 aws console이용해서 리눅스환경을 만들자

2. EC2인스턴스 생성(프리티어). 더불어서 key도 새로 만들어서 받아놓자.

3. 인바운드 규칙 편집.

인바운드란 ? 외부에서 -> 해당 서버(내경우에는 EC2서버) 로 들어올 수 있는 아이피 및 포트번호 설정. 주키퍼 및 카프카에서 해당 인스턴스에 접근할 수 있도록 포트번호와 아이피를 열어둔다. 이번은 시험용이니까 anywhere로 해도 괜찮지만.. 실제라면 ip를 특정해주는 것이 보안상 안전할 것이다! 

아웃바운드란 ? EC2서버 에서 -> 바깥 네트워크로 나가는 설정. 기본적으로모두열려있음. 

4. puttygen을 사용해서 private key를 만들고 저장한다.

5. putty를 사용해서 Auth란에 해당 프라이빗 키를 넣고, public ip 에 EC2의 ip를 넣고 접속한다.

6. 나는 이번에 amzon2타입인스턴스로 만들었기 때문에 - 기본적으로 유저네임은 ec2-user이다.


접속 성공.



자바 및 아파지 카프카 설치. wget 명령어(web상에 있는 파일을 다운로드 할 수 있게 해주는 명령어) 를 이용 + tar 명령어로 압축을 푼다. 

2021-09-03

0903 set, linkedList, map

 1. set 은 언제 사용하는가?

- 순서에 상관없이, 중복하지 않는 데이터를 저장

- 인덱스없이 그냥 해당 데이터가 존재하는지 존재하지 않는지만 확인하고 싶을 때 사용

- 구현한 주요 클래스로는 HashSet, TreeSet, LinkedHashSet이 있다.

1) HashSet : 가장 대표격인 Set클래스. 해쉬값으로 저장한다. 

2) TreeSet : 이진트리 + balanced Tree = 레드 블랙트리구조를 가진다.

이진트리의 장점 = 중위탐색으로 , 정렬된 결과를 반환할수있다. 루트의 하위 왼쪽 노드는 루트노드보다 작은 숫자, 루트의 하위 오른쪽노드는 루트노드보다 큰 숫자.

이진트리의 약점( depth가 n만큼 증가할 수 있다는 점) 을 보완하여, 조회삭제수정 연산에서 logn의 매우 향상된 성능을 보인다.


2. HashSet

- set의 생성자중 독특한 점 : load factor

- load factor란, 해당 셋에 얼마만큼 원소가 차있는가를 나타낸다. 이 값은 0.75로 자바에서는 셋팅되어있다(default 값, 사용자가 건드리지 않은 경우.) 

만약 set에 저장된 원소의 개수가 많아져서 0.75를 초과하게 될 경우, set의 크기는 2배로 resize되며 이 과정에서 다시 원소들의 해쉬값을 계산하고 새 배열로 이동하는 연산이 이루어진다. 이 과정에서 성능 하락 있을 수 있음. 0.75가 웬만하면 최적화된 수치라고 하니 적어두 근 몇년간 자바견습생이 건드릴 일은 아마 없을 것..ㅎㅎ


3. LinkedList

- list의 일종이자, queue와 deque를 구현하고 있다. 

- deque는 double ended queue이다.

- 배열 중간의 데이터가 수정/삭제 연산이 많이 이루어진다면, LinkedList를 사용하는 것을 고려해본다. 

- linkedList가 데려오는 iterator 는 두가지 종류가 있는데 , 일반적인 Iterator와 ListIterator 가 있다. ListIterator는 특이하게 previous() 가 가능하다. 원소의 앞뒤에 붙은 원소를 탐색할 수 있어야 하기 때문에. next()로 다음으로 가는 것도 가능하고 이전으로 가능것도 가능한 것이다.  


<Map>

1 . key, value를 가진다. key는 고유해야 하므로, equals와 hashcode를 구현해야 한다.

2. 만약 equals, hashcode를 구현하지 않은 타입을 key로 저장할경우 해당 객체의 메모리주소를 가지고 객체의 동일성을 판단하게 되므로, 논리적으로는 같아보이는 값이 여러번 저장될 것이다.

3. Map은 Collection에 속하지 않는다. put(), get()으로 넣고 뺀다.

4. keySet() 메소드로 key만 Set타입으로 뽑아볼 수 있다.

5. values() 메소드로 값만 Collection타입으로 뽑아볼 수 있다.

6. Map을 구현한 Properties클래스라는 것이 있다. 

1) 따라서 마찬가지로 key, value로 값을 저장한다.

2) 추가적으로, 데이터를 읽고 쓰기 위한 메소드들을 제공한다. 

3) system properties를 이 객체를 통해 확인해 볼 수 있다. ( encoding type, user.dir 같은 속성들..) 

2021-09-02

0902 Collections, List탐구

 1. 대표적인 자료구조 : List, Set, Queue, Map

List, Set, Queue는 Collection을 상속한다. Map만 따로.

2. List의 대표격인 - ArrayList가 있다.

3. List의 하나로 Stack이 있다. Stack 은 일반적인 list관련 메소드 + pop(), peek(), empty(), push()를 지원한다. Vector클래스를 상속하고 있기 때문이다. 

4. list에서 요소를 뽑아내는 방법은 크게 세가지를 들 수 있다.

1) iterator사용 2) for(int=0;i=list.size(); i++) 3)향상된 for문 사용

effective java에서는 3)을 쓸것을 권하고 있다. 보기에도 편하고 ( 2번보다의 장점) , iterater를 썼을때 변수가 많이 만들어져서 실수할 위험도 줄어든다 (1번보다의 장점)

단 알고리즘 풀이라든지. 인덱스정보가 필요한 경우 2를 사용할 수도 있겠다. 상황에 따라 적절한 메서드를 구현하자.

5. ArrayList의 생성자

1) new ArrayList() 

2) new ArrayList(int size)

배열의 크기를 지정할 수 있다.

3) new ArrayList(다른 리스트);

단 이것은 shallow copy이므로 사용에 주의한다. clone()메서드도 마찬가지로 shallow카피를 한다. 만약에 원본 객체의 값이 달라지면 모든 리스트에 파급효과가 미친다!!! 객체 자체를 담은 게 아니라, 객체의 주소를 담은 것이기 때문이다.

그러므로 의도치 않은 파급효과를 막고싶다면 - 카피하려는 객체 자체도 cloneable을 구현해주어야 한다. 




위와같이.. 원본객체 하나만 바뀌어도 다바뀐다. 이럼 완죤 망하는 거다. ㅜㅜ 어디서 값이 바뀐건지 추적도 쉽지않다. 값이 바뀌는 지점과 확인하는 지점이 멀어지면 멀어질수록- 디버깅은 힘들어지는 것이다.... (상상만 해도 무섭다;)

---------------------------------------------------------------------------------------------
6. arrayList -> 배열로 만들기
1) String[] str = (String[]) ArrayList().toArray();
이런식의 강제 캐스팅은 실패한다. toArray의 파라메터에 아무것도 넘기지 않으면
Object[] 타입을 리턴하기 때문이다. 
여기서 유의할 점은 - String은 분명히 Object의 하위타입이 맞다.
또한 String[]은 Obejct[]의 하위타입이 맞다.
그러므로 컴파일도 잘 된다. 
막나가서 - 해당 ArrayList안에 int타입이 들어가 있었다고 치자. 근데 그래도 컴파일 잘된다!!
그러다가 런타임에서 오류가 난다... 런타임에서는 String[]으로 변하기 때문이다. 
( 이래서 배열을 쓰지말구 제네릭을 이용한 Collection클래스를 권장하는 것이다. Collection은 런타임에서 이런 타입에러를 잡아주기 때문이다.)
배열은 공변, Collection은 불공변이다.

2) 그러므로 배열로 바꾸어야 할 일이있다면
toArray(new String[0])과 같이, 원하는 타입의 파라메터를 넣어준다.
해당 배열의 크기가 ArrayList의 size보다 작을 경우, 임의로 배열을 생성해서 값을 넣어준다. 

3) 아니면 java8문법 사용한다. streams api

0902 generic과 wildcard 2

 

1. wildcard는 메서드의 파라메터로서만 사용할 수 있다. 안그러면 저렇게 에러를 뱉는다.

return 값으로 ? 가 된다니 타입에 엄격한 자바세계에서는 말도 안된다!

알지도 못하는 타입으로 내가 어떻게 돌려주랴?! 하는 컴파일러의 툴툴거림이 들리는 듯하다.



2. Bounded경계를 정할 수 있다.

PECS원칙에 따라,producer-extends, consumer-super 


출처: https://starblood.tistory.com/entry/Java-PECS-producerextends-consumersuper-에-관하여 [Drink and Be happy]

하도록 설계한다. ( 이부분 어렵다. ㅜㅜ)



  이와같은 Car를 상속한 Bus 클래스가 있다.

Bus클래스는 자기만의 메소드 getPassenger를 추가로 가지고 있다.



3. 당연하게도 Bus타입만의 메소드는 부를 수 없다. 

4. 언제 ?를 사용하고, 언제 T 를 사용하는가

: ?는 보통 해당 원소의 데이터와 상관없을 때 사용한다고 한다. ?의 의미자체가, '들어오는 너가 어떤 타입이든 상관하지 않는다' 라는 뜻을 내포하고 있기 때문이다.

이를 테면 - <? extends Number> 같은 경우를 들수있겠다. 너가 어떤타입이든간에, Number의 하위타입이기만 하면된다. 그런뜻. 추측컨대 이러한 경우는 -  ?로 들어오는 타입의 기능을 사용하는 것이 아니라 Number의 기능만 있으면 되는 메서드 일 것이다.

물론 기능적으로는 <? extends Number>이라고 쓰던, <T extends Number> 이라고 쓰던, 똑같이 동작할 수도 있다. 하지만 어떠한 내용의 메소드를 구현하고자 하는지, 해당 목적에 따라 적절하게 타입파라메터를 작성하는 것이, 훨씬 명확해질 것이다.

0902 access log

 apache 의 경우, access_log 폴더 밑에 만들어진다.

이 로그는 액세스가 완료된 후 생성되기 때문에, 만약에 네트워크 장애로 정상적인 접속이 계속되서 지연될 경우 , 생성되지 않는다. 

이럴때는 L4를 끊은 후에, 다른 서버로 돌려주고, 로그를 찍고, 에러를 분석한다.

127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326

이제 로그 항목의 각 부분을 설명한다.

127.0.0.1 (%h)
서버에 요청을 한 클라이언트(원격 호스트)의 IP 주소이다. HostnameLookups가 On이라면 호스트명을 찾아서 IP 주소 자리에 대신 쓴다. 그러나 이 설정은 서버를 매우 느리게 할 수 있으므로 추천하지 않는다. 호스트명을 알려면 대신 나중에 logresolve와 같은 로그를 처리하는 프로그램을 사용하는 것이 좋다. 여기에 나온 IP 주소는 사용자가 사용하는 컴퓨터 주소가 아닐 수 있다. 프록시 서버가 사용자와 서버사이에 존재한다면, 원래 컴퓨터 주소가 아니라 프록시의 주소가 기록될 것이다.
- (%l)
출력에서 "빼기기호"는 요청한 정보가 없음을 나타낸다. 이 경우 여기에 나올 정보는 클라이언트 컴퓨터의 identd가 제공할 클라이언트의 RFC 1413 신원이다. 이 정보는 매우 믿을 수 없기때문에, 긴밀히 관리되는 내부 네트웍이 아니라면 절대로 이 정보를 사용하면 안된다. IdentityCheck가 On이 아니라면 아파치 웹서버는 이 정보를 알아보려고 시도하지도 않는다.
frank (%u)
이는 HTTP 인증으로 알아낸 문서를 요청한 사용자의 userid이다. 보통 이 값은 CGI 스크립트에게 REMOTE_USER 환경변수로 넘겨진다. 요청의 상태코드가 401이라면 (아래 참고) 사용자가 아직 인증을 거치지 않았으므로 이 값을 믿으면 안된다. 문서를 암호로 보호하지 않는다면 이 항목은 이전 항목과 같이 "-"이다.
[10/Oct/2000:13:55:36 -0700] (%t)
서버가 요청처리를 마친 시간. 형식은:

[day/month/year:hour:minute:second zone]
day = 숫자 2개
month = 숫자 3개
year = 숫자 4개
hour = 숫자 2개
minute = 숫자 2개
second = 숫자 2개
zone = (`+' | `-') 숫자 4개

로그 형식문자열에 %{format}t를 사용하여 다른 형식으로 시간을 출력할 수 있다. format은 C 표준 라이브러리의 strftime(3)과 같다.
"GET /apache_pb.gif HTTP/1.0" (\"%r\")
클라이언트의 요청줄이 쌍따옴표로 묶여있다. 요청줄은 매우 유용한 정보를 담고 있다. 첫째, 클라이언트가 사용한 메써드는 GET이다. 둘째, 클라이언트는 자원 /apache_pb.gif를 요청한다. 세번째, 클라이언트는 HTTP/1.0 프로토콜을 사용한다. 요청줄의 여러 부분을 따로 로그할 수도 있다. 예를 들어, 형식문자열 "%m %U%q %H"은 "%r"과 똑같이 메써드, 경로, 질의문자열, 프로토콜을 로그한다.
200 (%>s)
이는 서버가 클라이언트에게 보내는 상태코드이다. 이 정보는 (2로 시작하는 코드) 요청이 성공하였는지, (4로 시작하는 코드) 클라이언트에 오류가 있는지, (5로 시작하는 코드) 서버에 오류가 있는지 알려주므로 매우 중요하다. 상태코드의 전체 목록은 HTTP 규약 (RFC2616 section 10)에서 찾을 수 있다.
2326 (%b)
마지막 항목은 응답 헤더를 제외하고 클라이언트에게 보내는 내용의 크기를 나타낸다. 클라이언트에게 보내는 내용이 없다면 이 값은 "-"이다. 내용이 없는 경우 "0"을 로그하려면 대신 %B를 사용한다.

출처: https://httpd.apache.org/docs/2.4/ko/logs.html

0902 generic 과 wildcard

 

wildcard <?> 으로 선언한 객체를 특정타입(String)으로 지정하자 컴파일 에러가 난다.

알수없는 타입을 특정타입으로 지정하여 반환하는 것이 불가능하기 때문이다.



따라서 ?로 파라메터를 받을 경우, object로 반환하여야 컴파일 에러가 나지않는다.



만약 wildcard로 넘어오는 타입이 정해져있다면, 분기문을 이용하여 각각 처리해줄수도 있다.

0328 fdisk, mkfs, mount, fstab

 1. 하드디스크를 붙인다. 2. fdisk -l로 하드디스크를 확인한다.  - interactiive한 커맨드모드 사용하여 (m) 붙인 하드디스크의 파티셔닝을 한다.  - 마지막에 w를 해야 실제로 반영이 된다.  3. mkfs를 하여 어떤 파일시스...