Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Rubys의 이상한 Errno 예외 이해하기

Ruby의 예외 계층 구조를 살펴본 적이 있다면 이상한 점을 발견했을 수 있습니다. RuntimeError 및 NoMethodError와 같은 모든 일반적인 예외 외에도 Errno::*에 대한 이상한 참조가 있습니다. .

Exception
  StandardError
    ...
    SystemCallError
      Errno::*
    ...

디스크가 가득 찼을 때 디스크에 쓰기 작업을 하거나 실패한 네트워크를 통해 API 호출을 시도한 적이 있다면 이러한 유형의 오류가 실제로 발생하는 것을 보았을 것입니다. 존재하지 않는 파일을 열려고 시도하여 지금 바로 실행할 수 있습니다.

irb> File.open("badfilename.txt")
Errno::ENOENT: No such file or directory @ rb_sysopen - badfilename.txt
    from (irb):9:in `initialize'
    from (irb):9:in `open'
    from (irb):9
    from /Users/snhorne/.rbenv/versions/2.1.0/bin/irb:11:in `<main>'

그러나 Errono 예외는 정확히 무엇입니까? 그리고 다른 종류의 예외에 대해 다르게 취급하는 이유는 무엇입니까?

OS에 Ruby 적용

Errno 예외는 본질적으로 어댑터입니다. 운영 체제 오류를 Ruby의 예외 시스템에 연결합니다. 운영 체제는 Ruby와 다른 방식으로 오류를 처리하므로 일종의 어댑터가 있어야 합니다.

루비에서 오류는 예외로 보고되는 경향이 있습니다. 그러나 운영 체제 오류는 일반적으로 정수에 불과합니다. 따라서 루비는 가능한 각 OS 오류에 대해 하나의 예외 클래스를 정의합니다. 그런 다음 이러한 모든 예외를 모듈에 붙입니다. Errno라고 합니다.

IRB를 사용하여 이 모듈의 모든 예외를 볼 수 있습니다. 그리고 소년, 많이 있어요!

irb> Errno.constants
=> [:NOERROR, :EPERM, :ENOENT, :ESRCH, :EINTR, :EIO, :ENXIO, :E2BIG, :ENOEXEC, :EBADF, :ECHILD, :EAGAIN, :ENOMEM, :EACCES, :EFAULT, :ENOTBLK, :EBUSY, :EEXIST, :EXDEV, :ENODEV, :ENOTDIR, :EISDIR, :EINVAL, :ENFILE, :EMFILE, :ENOTTY, :ETXTBSY, :EFBIG, :ENOSPC, :ESPIPE, :EROFS, :EMLINK, :EPIPE, :EDOM, :ERANGE, :EDEADLK, :ENAMETOOLONG, :ENOLCK, :ENOSYS, :ENOTEMPTY, :ELOOP, :EWOULDBLOCK, :ENOMSG, :EIDRM, :ECHRNG, :EL2NSYNC, :EL3HLT, :EL3RST, :ELNRNG, :EUNATCH, :ENOCSI, :EL2HLT, :EBADE, :EBADR, :EXFULL, :ENOANO, :EBADRQC, :EBADSLT, :EDEADLOCK, :EBFONT, :ENOSTR, :ENODATA, :ETIME, :ENOSR, :ENONET, :ENOPKG, :EREMOTE, :ENOLINK, :EADV, :ESRMNT, :ECOMM, :EPROTO, :EMULTIHOP, :EDOTDOT, :EBADMSG, :EOVERFLOW, :ENOTUNIQ, :EBADFD, :EREMCHG, :ELIBACC, :ELIBBAD, :ELIBSCN, :ELIBMAX, :ELIBEXEC, :EILSEQ, :ERESTART, :ESTRPIPE, :EUSERS, :ENOTSOCK, :EDESTADDRREQ, :EMSGSIZE, :EPROTOTYPE, :ENOPROTOOPT, :EPROTONOSUPPORT, :ESOCKTNOSUPPORT, :EOPNOTSUPP, :EPFNOSUPPORT, :EAFNOSUPPORT, :EADDRINUSE, :EADDRNOTAVAIL, :ENETDOWN, :ENETUNREACH, :ENETRESET, :ECONNABORTED, :ECONNRESET, :ENOBUFS, :EISCONN, :ENOTCONN, :ESHUTDOWN, :ETOOMANYREFS, :ETIMEDOUT, :ECONNREFUSED, :EHOSTDOWN, :EHOSTUNREACH, :EALREADY, :EINPROGRESS, :ESTALE, :EUCLEAN, :ENOTNAM, :ENAVAIL, :EISNAM, :EREMOTEIO, :EDQUOT, :ECANCELED, :EKEYEXPIRED, :EKEYREJECTED, :EKEYREVOKED, :EMEDIUMTYPE, :ENOKEY, :ENOMEDIUM, :ENOTRECOVERABLE, :EOWNERDEAD, :ERFKILL, :EAUTH, :EBADRPC, :EDOOFUS, :EFTYPE, :ENEEDAUTH, :ENOATTR, :ENOTSUP, :EPROCLIM, :EPROCUNAVAIL, :EPROGMISMATCH, :EPROGUNAVAIL, :ERPCMISMATCH, :EIPSEC]

그런데 왜 이름이 그렇게 비밀스럽습니까? 내 말은, ENOINT가 "파일을 찾을 수 없음"을 의미한다고 어떻게 추측할 수 있습니까?

...실제로 아주 간단한 답이 있습니다.

libc에서 도매 복사

Errno 모듈을 처음 빌드한 사람은 libc에서 직접 오류 이름을 복사했습니다. 따라서 C에서 ENOINT는 OS가 파일을 찾을 수 없을 때 반환하는 정수 오류 코드를 포함하는 매크로의 이름입니다.

따라서 이들 각각이 무엇을 하는지 알아내기 위해서는 C 표준 라이브러리에 대한 문서를 살펴보는 것이 요령입니다. 여기에서 큰 목록을 찾을 수 있습니다. 아래에서 더 관련성이 높은 몇 가지를 발췌했습니다.

EPERM 작업이 허용되지 않습니다. 권한이 없으면 파일에 액세스할 수 없습니다.
에노엔트 파일 또는 디렉토리를 찾을 수 없습니다.
EIO 입력/출력 오류; 일반적으로 물리적 읽기 또는 쓰기 오류에 사용됩니다.
EBADF 잘못된 파일 설명자입니다. 예를 들어 읽기 전용으로 연 파일에 쓰려고 하면 이 오류가 발생합니다.
ECHILD 자식 프로세스를 조작하려고 했지만 하위 프로세스가 없습니다.
에노멤 RAM이 부족하여 더 이상 가상 메모리를 할당할 수 없습니다.
EACCES 허가가 거부되었습니다. 파일 권한이 시도한 작업을 허용하지 않습니다.
이노블럭 일반 파일을 HDD와 같은 장치로 마운트하려고 했습니다.
EBUSY 리소스가 사용 중입니다. 공유할 수 없는 시스템 리소스가 이미 사용 중입니다. 예를 들어, 현재 마운트된 파일 시스템의 루트인 파일을 삭제하려고 하면 이 오류가 발생합니다.
존재 파일이 존재합니다. 기존 파일이 새 파일을 지정하는 것만이 의미가 있는 컨텍스트에서 지정되었습니다.
ENOTDIR 디렉토리가 필요한 경우 디렉토리가 아닌 파일을 지정했습니다.
EISDIR 파일은 디렉토리입니다. 쓰기를 위해 디렉토리를 열거나 해당 디렉토리에 대한 하드 링크를 생성 또는 제거할 수 없습니다.
EINVAL 잘못된 인수입니다. 이것은 라이브러리 함수에 잘못된 인수를 전달할 때 발생하는 다양한 종류의 문제를 나타내는 데 사용됩니다.
EMFILE 현재 프로세스에 너무 많은 파일이 열려 있어 더 이상 열 수 없습니다. 중복된 설명자는 이 한도 계산에 포함됩니다.
EFBIG 파일이 너무 큽니다. 파일 크기가 시스템에서 허용하는 것보다 큽니다.
ENOSPC 장치에 남은 공간이 없습니다. 디스크가 가득 차서 파일에 대한 쓰기 작업이 실패했습니다.
에스파이프 유효하지 않은 탐색 작업(예:파이프).
EROFS 읽기 전용 파일 시스템에서 수정을 시도했습니다.
에피프 파손된 파이프; 파이프의 다른 쪽 끝에서 읽는 프로세스가 없습니다.
이노삭 소켓이 필요한 경우 소켓이 아닌 파일이 지정되었습니다.
ENETUNREACH 원격 호스트가 포함된 서브넷에 연결할 수 없기 때문에 소켓 작업이 실패했습니다.
ENETRESET 원격 호스트가 충돌하여 네트워크 연결이 재설정되었습니다.
이코노보트됨 네트워크 연결이 로컬에서 중단되었습니다.
이코노리셋 네트워크 연결이 원격 시스템 재부팅 또는 복구할 수 없는 프로토콜 위반과 같이 로컬 호스트의 제어를 벗어난 이유로 닫혔습니다.
ENOBUFS I/O 작업을 위한 커널 버퍼가 모두 사용 중입니다. GNU에서 이 오류는 항상 ENOMEM과 동의어입니다. 네트워크 작업에서 둘 중 하나를 얻을 수 있습니다.
아이스콘 이미 연결된 소켓을 연결하려고 했습니다. 연결을 참조하십시오.
이노트콘 소켓이 아무것도 연결되지 않았습니다. 먼저 데이터 대상을 지정하지 않고 소켓을 통해 데이터를 전송하려고 하면 이 오류가 발생합니다.
EDESTADDRREQ 소켓에 대해 기본 목적지 주소가 설정되지 않았습니다. 연결이 있는 데이터의 대상을 먼저 지정하지 않고 연결 없는 소켓을 통해 데이터를 전송하려고 하면 이 오류가 발생합니다.
종료 소켓이 이미 종료되었습니다.
ETIMEDOUT 지정된 시간 초과가 있는 소켓 작업이 시간 초과 기간 동안 응답을 받지 못했습니다.
절약 거절 원격 호스트가 네트워크 연결 허용을 거부했습니다(일반적으로 요청된 서비스를 실행하지 않기 때문에).
EHOSTDOWN 요청된 네트워크 연결에 대한 원격 호스트가 다운되었습니다.
EHOSTUNREACH 요청된 네트워크 연결에 대한 원격 호스트에 연결할 수 없습니다.
이노템프티 디렉토리가 비어 있지 않습니다. 비어 있는 디렉토리가 예상되는 곳입니다. 일반적으로 이 오류는 디렉토리를 삭제하려고 할 때 발생합니다.
에프로클림 이것은 새 프로세스에 대한 사용자당 제한이 시도된 포크에 의해 초과될 것임을 의미합니다. RLIMIT_NPROC 제한에 대한 자세한 내용은 리소스 제한을 참조하세요.