ในบทความ Linuxhint นี้ เราจะอธิบายว่าการเรียกของระบบคืออะไร ใช้ทำอะไร และอะไรที่ทำให้การเรียกเหล่านี้แตกต่างจากฟังก์ชันอื่นๆ ในไลบรารี C มาตรฐาน นอกจากนี้เรายังจะแสดงให้คุณเห็นว่าฟังก์ชันเหล่านี้ทำหน้าที่อะไรสำหรับเคอร์เนลในระบบ และวิธีที่กระบวนการใช้บริการที่พวกเขาให้ นอกจากนี้เรายังจะแสดงรายการการเรียกระบบที่ใช้บ่อยที่สุดพร้อมคำอธิบายสั้น ๆ ของแต่ละฟังก์ชันและส่วนหัวที่มีการประกาศ ในอีกส่วนหนึ่ง เราจะแสดงให้คุณเห็นวิธีการตรวจสอบการทำงานของการเรียกของระบบผ่านคอนโซลคำสั่ง
ตามแนวคิดแล้ว ระบบทั้งหมดประกอบด้วยเลเยอร์ต่างๆ ซึ่งแต่ละชั้นมีฟังก์ชันและสิทธิพิเศษของตัวเอง สแต็กของเลเยอร์ที่ประกอบกันเป็นระบบเริ่มต้นที่ระดับต่ำสุดด้วยส่วนประกอบฮาร์ดแวร์และสิ้นสุดที่ชั้นบนสุดซึ่งเรียกว่าโหมดผู้ใช้
โปรแกรมทั้งหมดที่เรารันบนคอมพิวเตอร์ของเราและโค้ดทั้งหมดเราเขียนและรวบรวมผลลัพธ์ในกระบวนการที่ทำงานในโหมดผู้ใช้ของระบบ ในโหมดนี้ ผู้ใช้ทำงานและดำเนินงานประจำวัน เปิดและใช้แอปพลิเคชันต่างๆ จัดการไฟล์ ฯลฯ ในระดับความปลอดภัย นี่เป็นเลเยอร์ที่ผิวเผินที่สุดของระบบ และด้วยเหตุนี้จึงเป็นเลเยอร์ที่ถูกจำกัดมากที่สุดและตามค่าเริ่มต้นจะถูกจำกัดโดยสิ้นเชิงในการจัดการและใช้ทรัพยากรระบบโดยตรง
ตามที่กล่าวไว้ข้างต้น เลเยอร์ฮาร์ดแวร์เป็นระดับต่ำสุดของระบบ ด้านบนสุดคือเคอร์เนล Linux เคอร์เนลเป็นหัวใจของระบบปฏิบัติการที่ทำงานร่วมกับฮาร์ดแวร์และจัดการอย่างเคร่งครัด โดยเป็นระบบปฏิบัติการเดียวที่มีสิทธิ์ในการทำเช่นนั้น ตัวอย่างเช่น กระบวนการและหน่วยความจำได้รับการจัดการที่นี่ เข้าถึงข้อมูลได้จากฮาร์ดดิสก์หรือ SSD อุปกรณ์เครือข่ายได้รับการควบคุม ฯลฯ ทุกสิ่งที่ระบบปฏิบัติการและกระบวนการทำกับฮาร์ดแวร์จะทำผ่านเคอร์เนล ดังนั้น คุณจึงสามารถพูดได้ว่าเป็นเฟิร์มแวร์ประเภทหนึ่งที่รวมซอฟต์แวร์และฮาร์ดแวร์เข้าด้วยกัน
เนื่องจากข้อจำกัดในการเข้าถึงและการจัดการทรัพยากรที่ระบบปฏิบัติการกำหนดไว้ในโหมดผู้ใช้ และเนื่องจากการเข้าถึงทรัพยากรเหล่านี้ทำได้ผ่านเคอร์เนลเท่านั้น กลไกที่ช่วยให้กระบวนการโต้ตอบกับทรัพยากรที่จำเป็นต้องใช้ในการทำงานจึงถือเป็นสิ่งสำคัญ
การเรียกของระบบหรือ SysCalls คือชุดของฟังก์ชันที่ระบบปฏิบัติการจัดทำขึ้นซึ่งทำหน้าที่เป็นส่วนต่อประสานระหว่างกระบวนการผู้ใช้และเคอร์เนล ฟังก์ชันเหล่านี้ช่วยให้เราสามารถโต้ตอบกับระบบปฏิบัติการและร้องขอบริการผ่านระบบปฏิบัติการที่ต้องใช้ทรัพยากรระบบ syscalls ไม่ให้สิทธิ์การเข้าถึงโดยตรงไปยังทรัพยากรหรือการจัดการ แต่เคอร์เนลจะเป็นผู้จัดการและทำให้พร้อมใช้งานสำหรับกระบวนการที่เรียกทรัพยากรเหล่านั้น แต่จะอยู่ภายใต้การจัดการที่เข้มงวดเสมอ
ในทางปฏิบัติ ฟังก์ชันการเรียกของระบบมีลักษณะเหมือนฟังก์ชันทั่วไปและถูกนำไปใช้ในลักษณะนั้น พวกเขามีอาร์กิวเมนต์อินพุตซึ่งข้อมูลที่จะประมวลผลจะถูกส่งไป และอาร์กิวเมนต์เอาต์พุตที่ระบบปฏิบัติการส่งคืนผลลัพธ์ให้
วิธีการเรียกใช้ฟังก์ชันประเภทนี้จะเหมือนกับฟังก์ชันอื่นๆ ที่เราพบในไลบรารี C ดังนั้น คำถามที่ว่ามันเป็นฟังก์ชันการเรียกหรือไม่ ในทางปฏิบัติ คำถามเชิงแนวคิดล้วนๆ สำหรับโปรแกรมเมอร์
อาร์กิวเมนต์ของฟังก์ชันเหล่านี้ใช้ประเภทมาตรฐานของภาษา C แม้ว่าโดยธรรมชาติของงานแล้ว สิ่งเหล่านี้มักจะเป็นตัวชี้ที่เก็บที่อยู่หน่วยความจำ ตัวอธิบาย เส้นทาง และอื่นๆ
บน Linux ขณะนี้มีการเรียกระบบประมาณ 350 ครั้ง นอกจากนี้ยังมีฟังก์ชันจำนวนมากที่ไม่ใช่การเรียกของระบบแต่จัดการทรัพยากรผ่านฟังก์ชันเหล่านั้น เช่น ฟังก์ชัน malloc(), free(), calloc() และ realloc() ที่จัดการหน่วยความจำแบบไดนามิกโดยใช้ syscalls ในโค้ดของคุณ
วิธีตรวจสอบการเรียกของระบบด้วยคำสั่ง Strace ในคอนโซล Linux
ตอนนี้คุณรู้แล้วว่าฟังก์ชันการเรียกของระบบคืออะไร ต่อไปเราจะแสดงวิธีตรวจสอบฟังก์ชันเหล่านี้แบบเรียลไทม์จากคอนโซลคำสั่ง Linux โดยใช้คำสั่ง "strace" คำสั่ง “strace” มีความยืดหยุ่นมาก ใช้เพื่อตรวจสอบระบบและมีตัวเลือกต่างๆ ที่คุณสามารถเห็นได้ด้วยคำสั่งต่อไปนี้:
เมื่อคุณรันคำสั่งนี้ รายการตัวเลือกการตรวจสอบที่นำเสนอโดย “strace” จะแสดงขึ้นในคอนโซลคำสั่ง

ในการมอนิเตอร์ syscalls ของกระบวนการ เราจำเป็นต้องรันด้วยคำสั่งต่อไปนี้:
สเตรค
strace ./กระบวนการ
อี -h
เพื่อทดสอบสิ่งนี้ เราได้รวบรวมโค้ดต่อไปนี้ที่เราให้ไว้เป็นตัวอย่างในบทความของเราชื่อ “ฟังก์ชันเชื่อมต่อในภาษา C” โค้ดนี้แม้จะเรียบง่าย แต่ก็น่าสนใจมากเพราะมันเชื่อมต่อเรากับโฮสต์ของ Google ผ่านบริการ HTTP และช่วยให้เราสามารถส่งคำสั่งและรับการตอบกลับได้
#รวม
#รวม
#รวม
#รวม
#รวม
#รวม
#รวม
#รวม
int หลัก (){
//ขั้นตอนที่ 1
int socket_id;
พอร์ต int =80;
ข้อผิดพลาด int;
บัฟเฟอร์ถ่าน [1025];
โครงสร้างโฮสต์ * เซิร์ฟเวอร์;
ลูกค้า struct sockaddr_in;
memset(&เซิร์ฟเวอร์, 0, ขนาดของ(เซิร์ฟเวอร์));
// ขั้นตอนที่ 2
เซิร์ฟเวอร์ =gethostbyname ( "www.google.com" );
ถ้า (เซิร์ฟเวอร์ ==NULL)
{
printf("\nเกิดข้อผิดพลาดในการรับข้อมูลโดเมน\n");
กลับ 1;
// ขั้นตอนที่ 3
socket_id =ซ็อกเก็ต ( AF_INET, SOCK_STREAM, 0 );
// ขั้นตอนที่ 4
ลูกค้า.sin_family =AF_INET;
client.sin_port =htons(พอร์ต);
// ขั้นตอนที่ 5
bcopy((ถ่าน *) เซิร์ฟเวอร์->h_addr,
(ถ่าน *) &client.sin_addr.s_addr,
ขนาดของ(เซิร์ฟเวอร์->h_length));
error=connect(socket_id, (struct sockaddr *) &client, sizeof(client));
ถ้า (ข้อผิดพลาด <0){
printf ("\nไม่สามารถสร้างการเชื่อมต่อกับเซิร์ฟเวอร์\n");
ปิด (socket_id);
กลับ 1;
printf ("\nเชื่อมต่อกับ :%s\n", inet_ntoa( client.sin_addr ));
ในขณะที่ (1){
printf("หากต้องการออก ให้กด Ctrl+c \nส่งคำสั่ง http:");
fgets (บัฟเฟอร์, 1,025, stdin);
ส่ง (socket_id, บัฟเฟอร์, 1025, 0);
memset(&บัฟเฟอร์, '\0', 1025);
รับ (socket_id, บัฟเฟอร์, 1025, 0);
printf("%s", บัฟเฟอร์);
memset(&บัฟเฟอร์, '\0', 1025);
เรารวบรวมโค้ดและตั้งชื่อเอาต์พุต "connect" ให้กับมัน จากนั้นเราดำเนินการด้วยคำสั่ง “./connect” และเติมคำสั่ง “strace” ไว้ข้างหน้าเพื่อให้สามารถตรวจสอบ syscalls ได้
คำสั่งนี้แสดง syscalls ของกระบวนการในคอนโซลคำสั่ง ดังที่เห็นในรูปต่อไปนี้ แม้ว่าโค้ดของเราจะใช้งานเฉพาะ socket(), เชื่อมต่อ(), send() และ recv() syscalls เท่านั้น การดำเนินการของมันจำเป็นต้องมีการเรียกระบบอื่นๆ ที่เกิดขึ้นในโค้ดของฟังก์ชันที่เราใช้

คำสั่งต่อไปนี้แสดงข้อมูลสรุปของการเรียกของระบบสำหรับกระบวนการเมื่อสิ้นสุด:

ฟังก์ชันการเรียกระบบสำหรับการจัดการกระบวนการ:
execlp()
เอ็กแซ็ค()
ดำเนินการ()
ดำเนินการ()
ดำเนินการ()
ตระกูลของการเรียกฟังก์ชันระบบที่แทนที่กระบวนการหนึ่งด้วยอีกกระบวนการหนึ่งโดยการสืบทอด PID และทรัพยากรจากกระบวนการหลัก unistd.hfork() ทำซ้ำกระบวนการ unistd.hgetpid() รับ PID ของกระบวนการที่เรียก unistd.hgetppid() รับ PID ของกระบวนการหลักของกระบวนการที่เรียกใช้ unistd.hexit() รายงานสถานะการออกของ process.stdlib.hgetcwd()getwd()
ส่งกลับสตริงที่มีไดเร็กทอรีการทำงานปัจจุบันของการเรียก process.unistd.hpause()หยุดกระบวนการชั่วคราวจนกว่าสัญญาณจะมาถึงunistd.hwait()รอเอาต์พุตของกระบวนการลูกจากกระบวนการพาเรนต์.wait.hฟังก์ชั่นการเรียกระบบสำหรับการจัดการไฟล์:
ฟังก์ชัน คำอธิบาย ส่วนหัว เปิด()openat()
Open files.fcntl.hclose()ปิด files.unistd.hread()Read files.unistd.hpoll()สำรวจความพร้อมใช้งานของไฟล์สำหรับการดำเนินการเฉพาะ poll.hwrite()เขียน files.unistd.hfcntl()จัดการไฟล์ descriptors.fcntl.htruncate()ftruncate()
ตัดทอนไฟล์ตามที่ระบุ lengthunistd.hcreat()สร้าง file.fcntl.hchmod()fchmod()
ตั้งค่าการอนุญาตของ filesys/stat.hunlink()Delete a file.unistd.hฟังก์ชั่นการเรียกของระบบสำหรับการจัดการสัญญาณ:
ฟังก์ชัน คำอธิบาย signal()เชื่อมโยงสัญญาณกับ handler.signal.hkill()ส่งสัญญาณไปยัง process.signal.hkillpg()ส่งสัญญาณไปยังกลุ่มของกระบวนการsignal.hraise()ดำเนินการการกระทำของสัญญาณในกระบวนการที่เรียกใช้ it.signal.hsigaction()ตั้งค่าการกระทำของ signal.signal.hsigwait()ระงับการดำเนินการของเธรดการเรียกจนกระทั่งสัญญาณที่ระบุ arrivals.signal.hsighold()เพิ่มสัญญาณให้กับกระบวนการเรียก ' signal mask.signal.hsigignore() ละเว้น signal.signal.hsigblock()บล็อก signal.signal.hpsignal()ซิกอินโฟ()
พิมพ์ข้อความพร้อมคำอธิบายของ signal.signal.hฟังก์ชั่นการเรียกระบบสำหรับการจัดการซ็อกเก็ต:
ฟังก์ชัน คำอธิบาย socket()สร้าง socket.socket.hbind()ผูกชื่อเข้ากับ socketsocket.hconnect()เชื่อมต่อ socket.socket.hlisten()ฟังการเชื่อมต่อบน socket.socket.haccept()ยอมรับการเชื่อมต่อบน socket.socket.hrecv()รับมาจาก()
recvmsg()
ได้รับข้อความจาก socket.socket.hsend()sendto()
sendmsg()
ส่งข้อความจาก socket.socket.hgetsockname() ส่งคืนที่อยู่ของซ็อกเก็ตเฉพาะโดย descriptor.socket.hgetsockopt() ตั้งค่าหรือรับตัวเลือกบน sockets.socket.hบทสรุป
ในบทความ Linuxhint นี้ เราได้อธิบายว่าฟังก์ชันการเรียกของระบบคืออะไร และใช้เพื่อร้องขอบริการเคอร์เนลที่เกี่ยวข้องกับการใช้ทรัพยากรระบบอย่างไร เราได้แสดงคำอธิบายสั้นๆ ให้กับคุณว่ากระบวนการของผู้ใช้คืออะไร และกระบวนการโต้ตอบกับเคอร์เนลผ่านการเรียกของระบบเป็นอย่างไร
เพื่อช่วยให้คุณนำคุณสมบัติเหล่านี้ไปใช้งานได้จริงอย่างรวดเร็ว เราได้รวมรายการการเรียกของระบบที่ใช้บ่อยที่สุด พร้อมด้วยคำอธิบายสั้นๆ และส่วนหัวที่คุณต้องรวมไว้ในโค้ดของคุณเพื่อใช้งาน นอกจากนี้เรายังรวมส่วนที่เราแสดงให้คุณเห็นวิธีการตรวจสอบ syscalls ของกระบวนการผ่านคอนโซลคำสั่ง