Lighttpd1.4.20 소스 분석 상태기(4) 오류 처리 및 연결 해제

15099 단어 lighttpd
Lighttpd에서 처리할 오류는 두 가지로 나뉩니다.하나는 http 프로토콜에 규정된 오류입니다. 예를 들어 404 오류입니다.다른 하나는 서버 실행 중의 오류입니다. 예를 들어 write 오류입니다.
http 프로토콜에 규정된 오류에 대해lighttpd는 해당하는 오류 알림 파일을 되돌려줍니다.사실lighttpd에 대해 말하자면, 이것은 잘못된 것이 아니다.오류 알림 파일을 되돌린 후 요청을 순조롭게 끝낸 셈이다. 클라이언트가 원하는 것과 결과가 다를 뿐이다.
서버 실행 중 오류의 경우 상태 기회가 CON_STATE_ERROR 상태.대부분의 경우, 이러한 오류는 클라이언트가 미리 연결을 끊어서 발생하는 것이다.예를 들어 페이지를 끊임없이 새로 고칩니다. 새로 고칠 때 이전의 연결이 완료되지 않았지만 브라우저에 의해 강제로 끊어지면 서버에 연결 오류가 발생합니다.서버의 경우 새로 고침 전후의 두 연결은 상관없다.따라서 서버는 다음 연결을 받을 때 이전 연결을 계속 처리합니다.이때 이전의 연결이 끊어져 연결 오류가 발생했습니다.CON_ 시작STATE_ERROR 상태 후에 이전 처리가 이미 결과를 얻었다면.http_status는 비어 있지 않습니다.그러면 플러그인_call_handle_request_done는 플러그인 요청 처리가 끝났다고 알려 줍니다.

  
    
/*
* even if the connection was drop we still have to write it to the
* access log
*/
if (con -> http_status)
{
plugins_call_handle_request_done(srv, con);
}

이어서 ssl을 사용하면 ssl 연결을 닫습니다.ssl 연결을 닫는 코드는 매우 길지만, 대부분은 오류 처리입니다.뒤로 가서 연결 모드가 DIRECT가 아니라면plugins_call_handle_connection_close는 플러그인 연결이 닫혔음을 알려 줍니다.여기, 연결이 설정되어 있지 않으면 keep_alive, 그러면 연결을 닫고 청소를 한 후에 상태기의 운행을 종료합니다.
keep_가 설정되어 있으면alive, 서버가 먼저 연결을 닫았을 수도 있습니다.shutdown을 호출하여 연결의 읽기와 쓰기를 닫습니다.끄기 오류가 없으면 상태 머신이 CON_ 로 들어갑니다.STATE_CLOSE 상태.

  
    
1      /*
2 * close the connection
3 */
4 if ((con -> keep_alive == 1 ) && ( 0 == shutdown(con -> fd, SHUT_WR)))
5 {
6 con -> close_timeout_ts = srv -> cur_ts;
7 connection_set_state(srv, con, CON_STATE_CLOSE);、
8 if (srv -> srvconf.log_state_handling)
9 {
10 log_error_write(srv, __FILE__, __LINE__, " sd " ,
11 " shutdown for fd " , con -> fd);
12 }
13 }

위의 코드에는 다음과 같은 문장이 있습니다: con->close_timeout_ts = srv->cur_ts;close_timeout_ts의 값은 현재 시간으로 설정됩니다.이때 왜 썼어요?조급해하지 말고 계속 끝내고 가세요.
CON_ 시작STATE_ERROR 상태 이후 keep_alive, 그리고 버퍼에 데이터가 아직 읽지 않았으니, 이 데이터를 읽고 바로 버려라.읽을 데이터가 없으면 close_time_ts는 0입니다.다음 코드를 실행합니다.

  
    
1 if (srv -> cur_ts - con -> close_timeout_ts > 1 )
2 {
3 connection_close(srv, con);
4 if (srv -> srvconf.log_state_handling)
5 {
6 log_error_write(srv, __FILE__, __LINE__, " sd " , " connection closed for fd " , con -> fd);
7 }
8 }

출력 로그를 제외하고 이 코드는connection_close.connection_close는 마지막 정리 작업을 합니다. close를 호출하여 대응하는connection을 버퍼에 다시 넣는 것을 포함합니다.앞에서 아까 말씀드렸듯이 CON_STATE_ERROR에 close_ 설정time_ts는cur_ts.CON_ 나왔습니다.STATE_ERROR 후 CON_STATE_CLOSE, 그동안cur_ts는 변하지 않았습니다.이전 코드에서 테스트 버퍼에 읽을 데이터가 없으면 const_time_ts는cur_와 같다ts.그러니까 상태기는 아직 CON_CLOSE_STATE 상태, 그리고 상태기의 큰 while 순환을 종료합니다.서버가 연결에 들어갔습니다_state_mechine 맨 뒤에 있는 switch 문장.이 switch에서 연결에 대응하는 fd가 fdevent 시스템에 추가되고 읽기 이벤트를 감청합니다.
이 시간에 연결이 꺼졌는데 읽을 게 뭐가 있겠어요?서두르지 마라!세심한 독자들은 이럴 때 서버가 연결에 대해shutdown 함수를 호출했을 뿐close 함수를 호출하지 않았다는 것을 알아차릴 것이다.우선 shutdown과close의 차이를 말씀드리겠습니다.close는 socket fd에 작용하고 다른 fd에 작용하는 효과가 많지 않습니다. 인용 계수를 줄이고 계수가 0일 때 자원을 방출하고 연결을 닫습니다.shutdown 함수는 socket fd를 위한 전문 함수입니다.shutdown은 socket 연결의 한 방향을 닫을 수 있습니다. 즉, 쓰기만 닫거나 읽기만 닫을 수 있습니다.또 다른 차이점은 연결이 여러 프로세스가 공유하는 경우 한 프로세스에서close를 호출하면 다른 프로세스가 연결을 사용하는 데 영향을 주지 않는다는 것이다. 인용 계수만 1이 줄어들기 때문이다.만약에 하나의 프로세스가 shutdown을 호출한다면 무작정 시스템이 이 연결을 없애고 다른 프로세스가 보는 것도 닫힌 연결이다.close의 socket fd,read,write 함수를 호출하면 이 fd에서 데이터를 읽거나 보낼 수 없습니다.shutdown의 socket fd를 호출했습니다. 버퍼에 읽을 수 있는 데이터가 있으면 프로세스에 socket fd가 닫히지 않았기 때문에read는 이 fd에서 데이터를 읽을 수 있습니다.shutdown은 연결을 닫았을 뿐이기 때문에 자원의 방출을 하지 않습니다. 연결이 차지하는 자원을 방출하려면close 함수를 호출해야 합니다.
keep_alive의 연결, 닫기는 서버가 자발적으로 시작합니다.TCP 프로토콜에 따라 자발적으로 종료를 시작한 쪽의 연결은 TIME_WAIT 상태입니다. 이 때 연결에 사용된 자원이 방출되지 않았습니다.더 비극적인 것은 이 상태에서 오랫동안 머물러야 한다는 것이다...(기본 4분) 병렬 서버의 경우 서버가 대량의 연결을 자발적으로 닫으면 서버의 자원이 곧 다 소모되고 (포트, 메모리 등) 새로운 연결을 만들 수 없습니다.이 TIME에 대해서_WAIT 상태, 독자 스스로 구글, 인터넷에 소개된 글과 처리 방법이 많습니다.비록 이 타임은_WAIT 상태는 우리에게 많은 번거로움을 가져다 줄 것 같지만, 이 상태가 없다면 우리는 더욱 번거로울 것이다...'UNIX Network Programming Volum1'이라는 신작에 대한 상세한 소개가 있으니, 관심 있는 독자들이 보실 수 있습니다.기왕 번거로움을 피할 수 없다면, 가능한 한 번거로움의 영향을 최소화해야 한다.연결이 차지하는 자원은 주로 포트와 메모리이다.포트는 어쩔 수 없어, 점용하면 점용해.하지만 메모리는 조금 절약할 수 있다.앞에서 말했듯이, shutdown 후에도 우리는 버퍼의 데이터를 읽을 수 있다.그러면 우리가 이 데이터를 읽은 후에 버퍼가 차지하는 메모리를 방출할 수 있다.메모리의 사용을 줄였다.
CON_에서STATE_CLOSE에서 다음 코드는 버퍼의 데이터를 읽습니다.

  
    
1 if (ioctl(con -> fd, FIONREAD, & b))
2 {
3 log_error_write(srv, __FILE__, __LINE__, " ss " , " ioctl() failed " , strerror(errno));
4 }
5 if (b > 0 )
6 {
7 char buf[ 1024 ];
8 log_error_write(srv, __FILE__, __LINE__, " sdd " , " CLOSE-read() " , con -> fd, b);
9
10 read(con -> fd, buf, sizeof (buf));
11 }
12 else
13 {
14 /*
15 * nothing to read
16 */
17
18 con -> close_timeout_ts = 0 ;
19 }

읽을 데이터가 없으면 close_ 설정timeout_ts는 뒤에 연결된 코드를 닫습니다.읽을 수 있는 데이터가 있으면 데이터를 읽은 후에도 연결이 CON_STATE_CLOSE 상태에서 연결에 대응하는 fd가 fdevent 시스템에 추가되어 읽기 이벤트를 감청합니다.버퍼에 데이터가 있다면connection_handle_fdevent 함수에도 위의 코드가 있습니다. 다시 실행합니다.데이터가 다 읽히지 않으면 서버는 연결에서 중복됩니다_handle_fdevent 함수에서 데이터를 다 읽을 때까지 상기 코드를 실행합니다.close_에 따라timeout_ts는 0으로 설정되었습니다. 다음joblist 스케줄링에서 상태기는 연결을 닫고 모든 자원을 정리합니다.
이로써 연결이 정식으로 닫힙니다.이렇게 번거로운 이유는 연결이 서버가 자발적으로 닫혔기 때문에 TIME_WAIT 상태에 대한 질문입니다.이렇게 처리하는 것은 단지 메모리에 약간의 절약이 있을 뿐이다.그러나 구체적인 효과가 어떠한지 시스템 핵이 연결 버퍼를 어떻게 처리하는지에 달려 있다.만약 독자 여러분이 이 방면의 내용을 이해한다면, 아낌없이 가르침을 주십시오!
또한 shutdown 이후 커널의 버퍼가 어떻게 될지 필자는 확실하지 않다.위의 내용은 코드에 근거하여 추단할 뿐이다.아니면 그 말이 독자를 위해 어떤 고견을 주신다면 아낌없이 가르침을 주시겠어요.

좋은 웹페이지 즐겨찾기