Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เข้าใจ Ruby Errno Exceptions: คู่มือปฏิบัติสำหรับการจัดการข้อผิดพลาดระบบ

หากคุณเคยดู hierarchy ของ Ruby exceptions คุณอาจสังเกตเห็นสิ่งแปลกๆ นอกจาก exceptions ธรรมดาเช่น RuntimeError และ NoMethodError แล้ว ยังมีการอ้างอิงถึง Errno::* อีกด้วย


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

หากคุณเคยเขียนข้อมูลลงดิสก์ที่เต็ม หรือพยายามเรียก API ผ่านเครือข่ายที่ล้มเหลว คุณน่าจะเคยเจอ error ประเภทนี้ คุณสามารถทดสอบได้ทันทีโดยพยายามเปิดไฟล์ที่ไม่มีอยู่จริง:


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 `
'

แต่ Errno exceptions คืออะไรจริงๆ? และทำไมจึงถูกจัดการแตกต่างจาก exceptions อื่นๆ?

การปรับ Ruby ให้เข้ากับระบบปฏิบัติการ

Errno exceptions เป็นตัวแปลง (adapter) ที่เชื่อมต่อข้อผิดพลาดของระบบปฏิบัติการ (OS) เข้ากับระบบ exception ของ Ruby OS จัดการข้อผิดพลาดแตกต่างจาก Ruby จึงจำเป็นต้องมีตัวแปลง

ใน Ruby ข้อผิดพลาดมักรายงานเป็น exceptions แต่ข้อผิดพลาดของ OS มักเป็นเพียงตัวเลขจำนวนเต็ม (integers) ดังนั้น Ruby จึงกำหนดคลาส exception หนึ่งสำหรับแต่ละรหัสข้อผิดพลาดของ OS แล้วนำ exceptions ทั้งหมดใส่ไว้ใน module ชื่อ Errno

เราสามารถใช้ IRB ดู exceptions ทั้งหมดใน module นี้ได้ และมีเยอะมาก!


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]

แต่ทำไมชื่อถึงลึกลับมาก? ฉันจะเดาได้อย่างไรว่า ENOENT หมายถึง "File not found"?

...คำตอบง่ายมาก

คัดลอกมาจาก libc โดยตรง

ผู้สร้าง module Errno คัดลอกชื่อ error มาจาก libc โดยตรง ดังนั้น ENOENT ใน C คือชื่อของ macro ที่เก็บรหัสข้อผิดพลาดจำนวนเต็มที่ OS คืนค่าเมื่อไม่พบไฟล์

เพื่อรู้ว่าแต่ละ error ทำอะไร วิธีคือดู documentation ของ C standard library นี่คือบางส่วนที่เกี่ยวข้องมากกว่า:

Error Code ความหมาย
EPERMOperation not permitted; ไม่สามารถเข้าถึงไฟล์ได้หากไม่มีสิทธิ์
ENOENTFile or directory not found
EIOInput/output error; ใช้สำหรับข้อผิดพลาดการอ่าน/เขียนทางกายภาพ
EBADFBad file descriptor; เช่นพยายามเขียนไฟล์ที่เปิดเฉพาะอ่าน
ECHILDพยายามจัดการ child process แต่ไม่มี child process ใดๆ
ENOMEMหน่วยความจำ RAM หมด ไม่สามารถจัดสรร virtual memory เพิ่มได้
EACCESPermission denied; สิทธิ์ไฟล์ไม่อนุญาตให้ทำ operation นั้น
ENOTBLKพยายาม mount ไฟล์ทั่วไปเป็น device เช่น HDD
EBUSYResource busy; system resource ที่แชร์ไม่ได้กำลังถูกใช้งาน
EEXISTFile exists; ระบุไฟล์ที่มีอยู่แล้วในบริบทที่ควรระบุไฟล์ใหม่
ENOTDIRระบุไฟล์ที่ไม่ใช่ directory เมื่อต้องการ directory
EISDIRFile is a directory; ไม่สามารถเปิด directory เพื่อเขียน หรือสร้าง/ลบ hard links ได้
EINVALInvalid argument; ใช้บ่งชี้ปัญหาต่างๆ จากการส่ง argument ผิดไปยัง library function
EMFILEProcess ปัจจุบันเปิดไฟล์เยอะเกินไป ไม่สามารถเปิดเพิ่มได้
EFBIGFile too big; ขนาดไฟล์เกินกว่าที่ระบบอนุญาต
ENOSPCNo space left on device; เขียนไฟล์ล้มเหลวเพราะดิสก์เต็ม
ESPIPEInvalid seek operation (เช่นบน pipe)
EROFSพยายามแก้ไขบน read-only file system
EPIPEBroken pipe; ไม่มี process อ่านจากปลายอีกข้างของ pipe
ENOTSOCKระบุไฟล์ที่ไม่ใช่ socket เมื่อต้องการ socket
ENETUNREACHSocket operation ล้มเหลวเพราะ subnet ของ remote host ไม่สามารถเข้าถึงได้
ENETRESETNetwork connection ถูก reset เพราะ remote host crashed
ECONNABORTEDNetwork connection ถูก abort โดย local
ECONNRESETNetwork connection ถูกปิดเพราะเหตุผลนอกเหนือจากการควบคุมของ local host
ENOBUFSKernel buffers สำหรับ I/O operations เต็มหมด
EISCONNพยายาม connect socket ที่เชื่อมต่อแล้ว
ENOTCONNSocket ไม่ได้เชื่อมต่อกับอะไรเลย
EDESTADDRREQไม่มี default destination address สำหรับ socket
ESHUTDOWNSocket ถูก shut down แล้ว
ETIMEDOUTSocket operation ที่มี timeout ไม่ได้รับ response ภายในเวลาที่กำหนด
ECONNREFUSEDRemote host ปฏิเสธการเชื่อมต่อ (มักเพราะไม่ได้รัน service ที่ร้องขอ)
EHOSTDOWNRemote host สำหรับ network connection ล้ม
EHOSTUNREACHRemote host ไม่สามารถเข้าถึงได้
ENOTEMPTYDirectory not empty เมื่อคาดหวังว่าเป็น directory ว่าง
EPROCLIMPer-user limit on new process จะถูกเกินโดย fork ที่พยายามทำ