परिचय
इस LinuxHint लेख में, हम बताएंगे कि सिस्टम कॉल क्या हैं, उनका उपयोग किस लिए किया जाता है, और वे C मानक लाइब्रेरी में अन्य फ़ंक्शन से क्या अलग हैं। हम आपको यह भी दिखाएंगे कि वे सिस्टम में कर्नेल के लिए क्या कार्य करते हैं और प्रक्रियाएं उनके द्वारा प्रदान की जाने वाली सेवाओं का उपयोग कैसे करती हैं। हम सबसे अधिक उपयोग किए जाने वाले सिस्टम कॉल की एक सूची भी दिखाएंगे जिसमें प्रत्येक फ़ंक्शन का संक्षिप्त विवरण और वह हेडर जिसमें वे घोषित हैं, शामिल है। एक अन्य खंड में, हम आपको दिखाएंगे कि कमांड कंसोल के माध्यम से सिस्टम कॉल के संचालन की निगरानी कैसे करें।
सिस्टम आर्किटेक्चर: उपयोगकर्ता मोड और कर्नेल
सैद्धांतिक रूप से, सभी सिस्टम लेयर्स से बने होते हैं जिनमें से प्रत्येक का अपना कार्य और विशेषाधिकार होते हैं। एक सिस्टम को बनाने वाली लेयर्स का यह स्टैक सबसे निचले स्तर पर हार्डवेयर घटकों से शुरू होता है और शीर्ष लेयर पर समाप्त होता जिसे उपयोगकर्ता मोड के रूप में जाना जाता है।
हमारे कंप्यूटर पर चलने वाले सभी प्रोग्राम और हमारे द्वारा लिखे और संकलित किए गए सभी कोड एक प्रक्रिया में परिणाम देते हैं जो सिस्टम के उपयोगकर्ता मोड में चलती है। इस मोड में, उपयोगकर्ता काम करता है और अपने दैनिक कार्य करता है, विभिन्न एप्लिकेशन लॉन्च और उपयोग करता है, फ़ाइलों का प्रबंधन करता है, आदि। सुरक्षा स्तर पर, यह सिस्टम की सबसे सतही परत है और इसलिए सबसे प्रतिबंधित है और डिफ़ॉल्ट रूप से सिस्टम संसाधनों को सीधे प्रबंधित और उपयोग करने के लिए पूरी तरह से सीमित है।
जैसा कि पहले उल्लेख किया गया है, हार्डवेयर लेयर एक सिस्टम का सबसे निचला स्तर है। इसके ठीक ऊपर लिनक्स कर्नेल है। कर्नेल ऑपरेटिंग सिस्टम का दिल है जहां यह हार्डवेयर के साथ एकीकृत होता है और सख्ती से इसका प्रबंधन करता है, ऐसा करने वाला एकमात्र विशेषाधिकार वाला होता है। उदाहरण के लिए, प्रक्रियाओं और मेमोरी को यहां प्रबंधित किया जाता है, हार्ड डिस्क या SSD से डेटा एक्सेस किया जाता है, नेटवर्क डिवाइस को नियंत्रित किया जाता है, आदि। OS और प्रक्रियाएं हार्डवेयर के साथ जो कुछ भी करती हैं वह कर्नेल के माध्यम से किया जाता है। इसलिए, आप कह सकते हैं कि यह एक प्रकार का फर्मवेयर है जो सॉफ्टवेयर और हार्डवेयर को एकीकृत करता है।
उपयोगकर्ता मोड पर ऑपरेटिंग सिस्टम द्वारा लगाए गए संसाधन पहुंच और प्रबंधन प्रतिबंधों को देखते हुए, और क्योंकि इन संसाधनों तक पहुंच केवल कर्नेल के माध्यम से संभव है, एक तंत्र जो प्रक्रियाओं को उन संसाधनों के साथ बातचीत करने की अनुमति देता है जिन्हें उन्हें कार्य करने की आवश्यकता होती है, आवश्यक है।
सिस्टम कॉल क्या हैं?
सिस्टम कॉल, या SysCalls, ऑपरेटिंग सिस्टम द्वारा प्रदान किए गए फ़ंक्शन का एक सेट है जो एक उपयोगकर्ता प्रक्रिया और कर्नेल के बीच एक इंटरफ़ेस के रूप में कार्य करता है। ये फ़ंक्शन हमें OS के साथ बातचीत करने और उसके माध्यम से एक सेवा का अनुरोध करने की अनुमति देते हैं जिसमें सिस्टम संसाधनों के उपयोग की आवश्यकता होती है। सिस्कॉल संसाधनों या उनके प्रबंधन तक सीधी पहुंच प्रदान नहीं करते हैं, लेकिन कर्नेल ही उन्हें प्रबंधित करता है और उन्हें उस प्रक्रिया के लिए उपलब्ध कराता है जो उन्हें कॉल करती है, लेकिन हमेशा उसके सख्त प्रबंधन के तहत।
व्यवहार में, सिस्टम कॉल फ़ंक्शन सामान्य फ़ंक्शन की तरह दिखते हैं और उस तरह से कार्यान्वित होते हैं। उनके पास इनपुट आर्गुमेंट होते हैं जिनमें प्रोसेस किए जाने वाले डेटा को भेजा जाता है, और आउटपुट आर्गुमेंट जिनमें ऑपरेटिंग सिस्टम परिणाम लौटाता है।
इस प्रकार के फ़ंक्शन को कॉल करने की विधि C लाइब्रेरी में मिलने वाले किसी भी अन्य फ़ंक्शन के समान है। इसलिए, प्रोग्रामर के लिए व्यवहार में यह सवाल कि यह कॉलिंग फ़ंक्शन है या नहीं, विशुद्ध रूप से सैद्धांतिक है।
इन फ़ंक्शन के आर्गुमेंट C भाषा के मानक प्रकारों का उपयोग करते हैं। हालांकि, उनके कार्य की प्रकृति के कारण, वे आमतौर पर पॉइंटर्स होते हैं जो मेमोरी एड्रेस, डिस्क्रिप्टर, पथ आदि संग्रहीत करते हैं।
लिनक्स पर, वर्तमान में लगभग 350 सिस्टम कॉल हैं। 또한, बड़ी संख्या में फ़ंक्शन हैं जो सिस्टम कॉल नहीं हैं लेकिन उनके माध्यम से संसाधनों का प्रबंधन करते हैं जैसे malloc(), free(), calloc(), और realloc() फ़ंक्शन जो आपके कोड में सिस्कॉल का उपयोग करके डायनामिक रूप से मेमोरी का प्रबंधन करते हैं।
लिनक्स कंसोल में strace कमांड से सिस्टम कॉल की निगरानी कैसे करें
अब जब आप जानते हैं कि सिस्टम कॉल फ़ंक्शन क्या हैं, तो आइए आपको दिखाते हैं कि "strace" कमांड का उपयोग करके लिनक्स कमांड कंसोल से रीयल-टाइम में उनकी निगरानी कैसे करें। "strace" कमांड बहुत लचीला है। इसका उपयोग सिस्टम की निगरानी के लिए किया जाता है और कई विकल्प प्रदान करता है जिन्हें आप निम्न कमांड से देख सकते हैं:
strace -h
जब आप इस कमांड को चलाते हैं, तो "strace" द्वारा प्रदान की जाने वाली निगरानी विकल्पों की सूची कमांड कंसोल में प्रदर्शित होती है।

किसी प्रक्रिया के सिस्कॉल की निगरानी करने के लिए, हमें इसे निम्न कमांड के साथ चलाने की आवश्यकता है:
strace ./process
इसे टेस्ट करने के लिए, हम निम्न कोड को संकलित करते हैं जिसे हमने अपने लेख "C भाषा में कनेक्ट फ़ंक्शन" में उदाहरण के रूप में दिया था। यह कोड, हालांकि बहुत सरल है, बहुत दिलचस्प है क्योंकि यह हमें HTTP सेवा के माध्यम से Google होस्ट से कनेक्ट करता है और हमें कमांड भेजने और प्रतिक्रिया प्राप्त करने की अनुमति देता है।
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int main() {
// चरण 1
int socket_id;
int port = 80;
int error;
char buffer[1025];
struct hostent *server;
struct sockaddr_in client;
memset(&server, 0, sizeof(server));
// चरण 2
server = gethostbyname("www.google.com");
if (server == NULL) {
printf("\nडोमेन डेटा प्राप्त करने में त्रुटि।\n");
return 1;
}
// चरण 3
socket_id = socket(AF_INET, SOCK_STREAM, 0);
// चरण 4
client.sin_family = AF_INET;
client.sin_port = htons(port);
// चरण 5
bcopy((char *)server->h_addr,
(char *)&client.sin_addr.s_addr,
sizeof(server->h_length));
error = connect(socket_id, (struct sockaddr *)&client, sizeof(client));
if (error < 0) {
printf("\nसर्वर से कनेक्शन स्थापित नहीं कर सके\n");
close(socket_id);
return 1;
}
printf("\nकनेक्टेड: %s\n", inet_ntoa(client.sin_addr));
while (1) {
printf("बाहर निकलने के लिए Ctrl+c दबाएं \nHTTP कमांड भेजें: ");
fgets(buffer, 1025, stdin);
send(socket_id, buffer, 1025, 0);
memset(&buffer, '\0', 1025);
recv(socket_id, buffer, 1025, 0);
printf("%s", buffer);
memset(&buffer, '\0', 1025);
}
}
हम कोड को संकलित करते हैं और इसे "connect" आउटपुट नाम देते हैं। फिर, हम इसे "./connect" कमांड के साथ निष्पादित करते हैं और सिस्कॉल की निगरानी करने के लिए "strace" कमांड को पहले जोड़ते हैं।
यह कमांड कमांड कंसोल में प्रक्रियाओं के सिस्कॉल प्रदर्शित करता है। जैसा कि निम्न आकृति में देखा गया है, हालांकि हमारे कोड ने केवल socket(), connect(), send() और recv() सिस्कॉल का उपयोग किया, इसके निष्पादन के लिए अन्य सिस्टम कॉल की आवश्यकता होती है जो हमारे द्वारा उपयोग किए जाने वाले फ़ंक्शन के कोड में होते हैं।

निम्न कमांड किसी प्रक्रिया के समाप्त होने पर उसके सिस्टम कॉल का सारांश प्रदर्शित करता है:

सामान्यतः उपयोग किए जाने वाले सिस्टम कॉल
प्रक्रिया प्रबंधन के लिए सिस्टम कॉल फ़ंक्शन
| फ़ंक्शन | विवरण | हेडर |
|---|---|---|
| execl() execlp() execle() execv() execvp() execvpe() | सिस्टम फ़ंक्शन कॉल का परिवार जो पैरेंट प्रक्रिया से PID और संसाधनों को विरासत में लेकर एक प्रक्रिया को दूसरी से प्रतिस्थापित करता है। | unistd.h |
| fork() | एक प्रक्रिया को डुप्लिकेट करता है। | unistd.h |
| getpid() | कॉलिंग प्रक्रिया का PID प्राप्त करता है। | unistd.h |
| getppid() | कॉलिंग प्रक्रिया की पैरेंट प्रक्रिया का PID प्राप्त करता है। | unistd.h |
| exit() | प्रक्रिया की निकास स्थिति की रिपोर्ट करता है। | stdlib.h |
| getcwd() getwd() | कॉलिंग प्रक्रिया की वर्तमान कार्यशील डायरेक्टरी के साथ एक स्ट्रिंग लौटाता है। | unistd.h |
| pause() | सिग्नल आने तक प्रक्रिया को रोकता है। | unistd.h |
| wait() | पैरेंट प्रक्रिया से चाइल्ड प्रक्रिया के आउटपुट की प्रतीक्षा करें। | wait.h |
फ़ाइल प्रबंधन के लिए सिस्टम कॉल फ़ंक्शन
| फ़ंक्शन | विवरण | हेडर |
|---|---|---|
| open() openat() | फ़ाइलें खोलें। | fcntl.h |
| close() | फ़ाइलें बंद करें। | unistd.h |
| read() | फ़ाइलें पढ़ें। | unistd.h |
| poll() | किसी विशिष्ट ऑपरेशन के लिए फ़ाइलों की उपलब्धता को पोल करता है। | poll.h |
| write() | फ़ाइलें लिखें। | unistd.h |
| fcntl() | फ़ाइल डिस्क्रिप्टर में हेरफेर करता है। | fcntl.h |
| truncate() ftruncate() | किसी फ़ाइल को निर्दिष्ट लंबाई तक काटता है। | unistd.h |
| creat() | एक फ़ाइल बनाता है। | fcntl.h |
| chmod() fchmod() | फ़ाइल की अनुमतियाँ सेट करता है। | sys/stat.h |
| unlink() | एक फ़ाइल हटाता है। | unistd.h |
सिग्नल हैंडलिंग के लिए सिस्टम कॉल फ़ंक्शन
| फ़ंक्शन | विवरण | हेडर |
|---|---|---|
| signal() | एक सिग्नल को हैंडलर से लिंक करता है। | signal.h |
| kill() | किसी प्रक्रिया को सिग्नल भेजता है। | signal.h |
| killpg() | प्रक्रियाओं के समूह को सिग्नल भेजता है। | signal.h |
| raise() | इसे कॉल करने वाली प्रक्रिया में सिग्नल की कार्रवाई करता है। | signal.h |
| sigaction() | सिग्नल की कार्रवाई सेट करता है। | signal.h |
| sigwait() | निर्दिष्ट सिग्नल आने तक कॉलिंग थ्रेड के निष्पादन को निलंबित करता है। | signal.h |
| sighold() | कॉलिंग प्रक्रिया के सिग्नल मास्क में सिग्नल जोड़ता है। | signal.h |
| sigignore() | एक सिग्नल को अनदेखा करता है। | signal.h |
| sigblock() | एक सिग्नल को ब्लॉक करता है। | signal.h |
| psignal() psiginfo() | सिग्नल के विवरण के साथ एक संदेश प्रिंट करता है। | signal.h |
सॉकेट हैंडलिंग के लिए सिस्टम कॉल फ़ंक्शन
| फ़ंक्शन | विवरण | हेडर |
|---|---|---|
| socket() | एक सॉकेट बनाता है। | socket.h |
| bind() | एक सॉकेट को एक नाम से बांधता है। | socket.h |
| connect() | एक सॉकेट को कनेक्ट करता है। | socket.h |
| listen() | एक सॉकेट पर कनेक्शन के लिए सुनता है। | socket.h |
| accept() | एक सॉकेट पर कनेक्शन स्वीकार करता है। | socket.h |
| recv() recvfrom() recvmsg() | एक सॉकेट से संदेश प्राप्त करता है। | socket.h |
| send() sendto() sendmsg() | एक सॉकेट से संदेश भेजता है। | socket.h |
| getsockname() | इसके डिस्क्रिप्टर द्वारा विशिष्ट सॉकेट का पता लौटाता है। | socket.h |
| getsockopt() | सॉकेट पर विकल्प सेट या प्राप्त करता है। | socket.h |
निष्कर्ष
इस LinuxHint लेख में, हमने बताया कि सिस्टम कॉल फ़ंक्शन क्या हैं और कैसे वे कर्नेल सेवाओं का अनुरोध करने के लिए उपयोग किए जाते हैं जिनमें सिस्टम संसाधनों का उपयोग शामिल है। हमने आपको एक संक्षिप्त व्याख्या दिखाई कि उपयोगकर्ता प्रक्रियाएं क्या हैं और वे सिस्टम कॉल के माध्यम से कर्नेल के साथ कैसे बातचीत करती हैं।
आपको इन सुविधाओं को जल्दी से व्यवहार में लाने में मदद करने के लिए, हमने सबसे अधिक उपयोग किए जाने वाले सिस्टम कॉल की एक सूची शामिल की है जिसमें प्रत्येक का संक्षिप्त विवरण और वह हेडर शामिल है जिसे आपको अपने कोड में शामिल करने की आवश्यकता है ताकि आप उनका उपयोग कर सकें। हमने एक खंड भी शामिल किया जहां हमने आपको दिखाया कि कमांड कंसोल के माध्यम से किसी प्रक्रिया के सिस्कॉल की निगरानी कैसे करें।