UNIX programming article

xiaoxiao2021-03-05  47

Just organized a UNIX programming article, and shared it with everyone. I hope to help everyone.

Author: sysvol Posted: 2002/02/07 10:26 am

Note: Chapter VII Process Communication Hu Yongliang

UNIX programming information

Chapter 1 Overview 1.1Unix 's version UNIX operating system is the development of C language in the end of the 1960s. After decades of development, it has become an operating system that is popular with a variety of platforms such as mainframe, small machines to workstation or even microcomputers. The success of UNIX also promoted the popularity of C language. The purpose of this textbook is to explain the C program design under the UNIX system, so that C programmers quickly master programming under UNIX systems. During the practice of UNIX programming, the author is an importance of deep instances - a short C language example is often more than a long-tired text description, of course, text description is essential. This textbook will make you get started quickly to UNIX programming in the principle of instance priority.

The Unix version is not uniform. From UNIX development history, there are two major genres: AT & T's Unix System V version and the BSD version of the University of California Berkeley. On this basis, all UNIX vendors are all Developed their respective UNIX operating systems. Such as: Workstation manufacturers have HPUX, SUN Solaris, SGI Irix, IBM AIX, etc., small machines have ULTRIX on VAX, Microcomputers include Scounix, Microsoft's Xenix, and Linux, which is popular with Internet. Since WindowsNT has a huge threat to UNIX's market, major Unix manufacturers have to join, in the workstation market, unified as standards in the system V version, join some of the advantages in the BSD version, support unified CDE (Commondesktop) Environment window environment to confront the Windows NT.

1.2 UNIX programming environment

The UNIX operating system implements the interaction of the system with the user through the shell program. Under the shell prompt, the user typed the UNIX command to obtain the output result of the operating system. The common shell of the BSD system is C shell. The default prompt is "%". The common shell of system V is Bourne Shell (now Kornshell), the default prompt is "$", about shell programming, we are behind The chapter is introduced.

The standard compiler on UNIX is CC. Type the following command under the Shell prompt (as an example of C shell):% cc -o hello hello.c

The c file Hello.c is compiled as an executable file Hello. The Unix provides command Make when compiling multiple files to generate an executable. Users need to write a text file called Makefile in a certain format for multiple C files. The following is an example of a makefile on SGI: cc = cccflags = $ (debug) -cckr -i $ (inc) / x11 -dsysvdebug = -ginc = / usr / incruDeldflags = -lxext -lxm -lxt -lx11 -lpw - LCOBJS = INITX.O WINDOWX.otgts = showxwin

All :: $ (TGTS) SHOWXWIN: $ (OBJS) $ (CC) -O $ @ $ (oj) $ (cflags) $ (ldflags)

The string of uppercase letters is some macro. CC is the name of the compiler. CFLAGS defines the compilation switch of the CC. Debug is a debug macro. Inc is the directory where the header file is located. The OBJ defines the target file name, TGTS Define the executable file name. Type directly in the shell prompt:% make, you can compile all the C files specified in Makefile and generate an executable.

1.3 The basic concepts in UNIX programming first need to clarify the system call and library functions before discussing UNIX programming. A system call refers to a request that requires an operating system represents a user program to perform some tasks. For example: READ is a system call, which requests an operating system to store data on a disk device (or other device) to populate a buffer. If anyone can access the device casually when they want to perform the task, then the consequences will be unpredictable. Therefore, this service must request an operating system to do (often transparent) record all requests for each device. And a library function does not often require an operating system to perform its tasks. For example, SIN (), COS (), etc. in the math library function, etc., these calculations only need to simply ask for a limited sequence, so do not require operating system intervention. In UNIX operating systems, there is a common command man, which can be used to consult the specific use of commands, library functions, and system calls. Traditional UNIX Online Help Handbook is: 1 User-Level Commands 2 System Call (System Calls) 3 Library Function (DEVICES AND DRIVERS) 5 File Format ( File Formats 6 Games 7 Miscellaneous (Various Miscellaneous Stuff - Macro Packages etc. 8 System Maintenance and Operation Command (System Maintenance and Operation Commands)

Chapter 2 Standard Input / Output Library

2.1 Overview

This chapter introduces Unix standard input / output library, UNIX provides some library functions to complete advanced input / output, providing programmers with three main functions: · Automatically open the buffer. Even if only a few bytes read or written, the library function is still executing actual input or output in "block" composed of thousands of bytes (buffer size is usually buffs in the head file stdio.h. definition). This buffer is used inside to use the library function, which is transparent to programmers;

· Automatically perform input and output conversion.

· The input and output is automatically formatted. The above two points are generally in the tutorial of the C language.

In the standard input / output library, a file is called a string of textuals, and is described by a target pointer pointing to the type File, the pointer is referred to as a file pointer. In the Unix in the field pointer stdin, stdout, stderr is a pre-defined, corresponding to standard input (keyboard), standard output (terminal screen), and standard error output.

2.2 Library function introduction

· File creation and closing FOPEN () Used to open existing files or create new files

· Document reading and writing 1, handle a character getc (), PUTC () 2, handle multiple characters fgets (), fputs () 3, files for two-way read / write full (), fwrite () 4, file format Input / output FSCANF (), FPRINTF () 5, string formatting input / output SSCANF (), SPRINTF ()

· File movement positioning The standard input / output library function for mobile in the file is fseek (), which receives three parameters: a file pointer points to an open character stream; an integer indicates the number of bytes to be moved, called OFFSet An integer indicates what positions from the file move. Chapter 3 Low-level Input / Output

3.1 Overview

Corresponding to the second chapter, this chapter describes the input / output implemented by system calls in the UNIX system, which is often called low input / output. These system calls can directly implement inputs and outputs of devices such as tape drives, and programmers can determine the size of the buffer to be used, not as transparent to the buffer size as the standard input / output library function.

In the standard input / output library, a file corresponds to a file pointer. When using a low-level interface, use a file description word to correspond to one file. The file description word is a small integer. There are three pre-defined file descriptions 0, 1, and 2, respectively, corresponding to standard input, standard output, and standard error output, respectively. Generally speaking, the file description is given as the first parameter of the system call.

3.2 Related System Call Introduction

· File creation and closing open () is used to open a file for read and write, or use it to create a new file. INT OPEN (const char * path, int rug, ... / * mode * /); Open uses three parameters: a string PATH contains file names to open; an integer OFLAG indicates how file will be opened; an integer Mode is used when creating a file. Commonly used OFLAG includes: o_rdonly open files are for reading only. O_Wronly opens the file for only to write. O_RDWR Opens the file for reading and writing. O_CREAT If the file does not exist, then create, at this time, Mode is given as a third parameter. Close () is used to close an open file.

· Document reads and writes read () for reading files, formats: read (int Fildes, void * buf, size_t nbyte); three parameters are as follows: filedes is a file description word; pointer BUF points to a data will be read Buffer; integer nbytes indicate the number of bytes to read. Returns the number of bytes actually read when successfully, returns -1. Write () is used to write files, similar to read, format: Write (int Fildes, Void * buf, size_t nbyte); three parameters are as follows: filedes is a file description word; pointer BUF points to a data will be written Buffer; integer nbytes indicate the number of bytes to be written. Returns the number of bytes that actually written during success, returns -1.

· File Mobile Location For the low-level input / output system call to move in the file is LSeek (), similar to fseek (), which also receives three parameters: a file description word corresponding to an open file; an integer indicates to move The number of bytes is called OFFSet; an integer indicates what location moves from the file.

· Copying file descriptions Sometimes there is a file corresponding to a file description word. This is often used when creating a sub-process (at the following chapter on the process development). In order to get a new file description word, and ensure that it corresponds to the same file, the FD2 = DUP (FD) FD2 should now be corresponding to the FD corresponding to the same file, and there is the same location in the file as the FD.

Chapter 4 Files and Directory Programming 4.1 Basic Concepts · File Directory Overview File System is a contribution of UNIX to computer technology! The file management of the UNIX system is very flexible, powerful, and many of the concepts that appear in the UNIX system are employed by other operating systems, such as MS-DOS, etc.

The UNIX system provides a hierarchical directory. Like the cabinets stored in a set of files, the directory can also be included in other directories, thus forming a huge, branching, which is often referred to as a tree structure. The directory is actually a special file. Commands, data files, other commands, even devices (special files) can be used as items (files) in the directory. I identification number, I list, and i node a directory consisting of a series of structures; each structure contains a file name and a pointer to file itself, which is an integer called a file I identification number. When the file is accessed, its I identification number is used as an index to open a system table (list), and the entity of the file (I node) is placed in the system. The i node contains a description of the file: • File itself user and user group ID · The protection code of the user group ID · file · The physical disk address of the file content, the size of the file, the last I node changes, the last use and modification Time · Connect the number of files, that is, the number of times it appears in other directories · A tag (directory, ordinary file, special file), file type, the three-level protection of the file

Unix divides users using files into three levels: file owners, group users, and other users. The file owner also said that the file owner is the creation of the file. It has all the privileges for the file; the same group user is all users with the same identification number, and the file owner can determine which group belongs to which group and the group user Access rights; other users refer to users that are independent of the file main, and they are not in the same user group with the file owner, and other users will be determined by the file.

A file's access is stored in the di_mode domain of the file I node, Di_Mode's 0-8 digits represents the file owner, file group users, and other users' access rights to the file. For example, use the "LS-L" command to list the mode and attributes of the file hello.c:

-RWXR-XR-X 1 YDS User 58 September 25th 10:54 Hello.c

The leftmost column shows the mode of the file: the file master reads (R), writable (W), executable (X), the same group user reads, executable, other users File readable, executable. Corresponding, 0-8 bits of Di_Mode are 111101101 (0755).

4.2 Document Programming Introduction

· Check Access Permissions - Access System Call

The format of Access system calls is:

#include int access (const char * path, int us);

Where: Parameter PATH indicates the path to the file being checked, and the parameter AMODE points to access. Access determines whether the actual user of the calling process has access to the file PATH with Amode, if there is a corresponding permissions, the Access returns 0, otherwise returns -1.

Parameter AMODE can take the following values ​​or their logic "or": r_ok check read permissions W_OK Check the write permission X_ok check the execution (Search) Permissions f_ok Check if the file exists

For example: Access ("Hello.c", r_ok | w_ok), used to check if the actual user has read / write rights to file hello.c; "Hello.c", f_ok) determines if the file Hello.c exists.

· Link and delete files - Link and Unlink system call

The format of the link and unlink system calls is:

#include int link (const char * path1, const char * path2); int unlink (const char * path); where parameter PATH1 indicates that the file path name to be linked, Path2 points out to establish Link file. Link implements the link to Path2 to Path1, which is equivalent to a alias for Path1, and the link count of the file Path1 plus 1. Returns 0 if successful, otherwise returns -1.

The parameter PATH indicates the file path name to be deleted. Unlink deletes the file pointed out by PATH, if success, return 0, otherwise returns -1.

· Get ​​information from I node -stat and FSTAT system call

The call format of STAT and FSTAT is:

#include #include int stat (const char * path, struct stat * buf); int Fstat (int Fildes, Struct Stat * buf);

Note: STAT and FSTAT are used to obtain relevant status information in the file I node. STAT searches for the file path name given by the parameter PATH, and the FSTAT describes the corresponding I node based on the file description word given by the parameter Fildes. Both calls put the information reorganized from the I node and put into the STAT structure directed to the parameter BUF (the description of the STAT structure in File /usR/include/sys/stat.h). These two calls are successfully returned to 0, otherwise, -1 is returned.

STAT and FSTAT calls are very similar in use or in terms of use, and there is a point in parameters. Let's take an example below.

/ * statfile.c * / # include #include #include #include

Main (argc, argv) int Argc; char * argv []; {INT fd; struct stat statbuf; if (argc! = 2) {Printf ("usage: statfile filename! / n"); exit (1);} IF ((fd = fopen (argv [1], o_rdonly) == -1) FPrintf (stderr, "cannot open% s! / n", argv [1]); if (unlink (argv [1]) = = -1) FPrintf (stderr, "cannot unlink% s! / N", argv [1]); if (stat (argv [1], & statbuff) == -1) / * by file name * / fprintf (stderr , "Stat% S Fails As IT Should! / N"); ElsePrintf ("Stat% S succeed! / n", argv [1]); if (fstat (fd, & statbuf) == -1) / * by file Descriptor * / fprintf (stderr, "fstat% s fails! / n", argv [1]); ElsePrintf ("fstat% s succeeds as it should! / n", argv [1]);}

The program first opens the file specified in the command line, and then remove the file with unlink, then use the STAT and the FSTAT system to acquire the information. Suppose there is a file called xxx.c under the current command, running% statfile xxx.c

Once, the following results will be output:

Stat xxx.c fails as it will! fstat xxx.c succeeds as it sold!

As can be seen, after an open file is deleted, information is not available with STAT. FSTAT can get the information of the file. This is because the file name has been removed from the directory after UNLINK, and the file name cannot be found, and the file description is saved because the file is still open. Therefore, STAT cannot be successfully returned, but FSTAT can still return.

Use STAT call to determine which file type is quite useful when a file is file type. For example, the following code:

Stat ("Hello", & statbuf; if (statbuf.st_mod & s_ifi) == s_ifdir) Printf ("this is a directory file! / n"); Else IF (statbuf.st_mod & s_ifi) == s_ifreg) Printf "This is a regular file! / N"); ELSE ...

The above code can determine if the Hello file in the current directory is a directory file or other type of file.

4.3 Directory Programming Introduction

UNIX is also considered a file as a file, called a directory file, and manages and protects with ordinary files. Files such as Open, Close, Read, Lseek are valid for the directory files. The various system calls in the previous file program are equally valid for the directory. But compared to ordinary files, some of the catalogs have some of their own characteristics:

The read / write / execution access / write / execution access rights of the directory file has a special meaning: read rights allows the user to read the contents of the directory item; write permissions allow users to create or delete a file; execute permissions Allow users to retrieve directory (now the directory Search permissions).

The creation of the directory, delete and normal files are different, in addition, any users cannot write to the directory file to write to write operations.

· Create and delete - MKDIR and RMDIR system calls

The format of MKDIR and RMDIR system calls is:

#include #include int mkdir (const char * path, mode_t mode);

#include int RMDir; Const Char * PATH;

Where: Parameter PATH points out the file name of the directory file to create and delete. The parameter MODE in the MKDIR call indicates the file mode of the newly created directory file. After the new creation of the directory, except "." And "..", an illegal directory entry; when deleting the directory, the directory is required to be "." And "..", there is no other directory item. . When these two systems call Access to successfully returns 0, otherwise, -1 is returned.

· Reading the directory - Opendir / readdir / closedir library function

The directory file can be used as a normal file, first use the system call Open to open in a read mode, and then call the contents to read. At the same time, since the directory file is composed of a directory item with a directory structure, it is not convenient to read its content with read. UNIX provides library functions OpenDir / readdir / closedir, etc., can easily implement directory read. The function description is as follows:

#include #include DIR * OPENDIR (Char * filename); Struct Direct * ReadDir (Dir * Dirp); Void CloseDir (Dir * Dirp); Description: Parameter filename points out The directory path name to be opened, the library function OpenDir returns a pointer to the struct DIR (defined in file /usr/include/sys/dir.h). Both the library function readdir and Closedir are used as a parameter in this pointer, where readir returns a pointer to the structural Direct. The operations of the directory can be based on this pointer. Here is an example to find files named "name" in the current directory.

LEN = Strlen (Name); DIRP = OPENDIR ("."); if (DIRP == NULL) {Return NOT_FOUND;} while ((DP = readdir (DIRP))! = null) {if (dp-> d_namlen = = LEN &&! STRCMP (DP-> D_NAME, NAME)) {Closedir (DIRP); RETURN Found;}} closed;

The library function closedIR closes the open directory. It is worth noting that the above small code is very practical in the program, and the simple command similar to "LS" can be realized under Unix. Chapter 5 Basic Process Programming

5.1 Overview

UNIX systems provide programmers with a powerful tool: perform another program in a program. The easiest way to perform a program is to use the library function system. This function uses a parameter: a string containing the command to be executed. This function of this library is to use and use it. It is useful when calling a simple UNIX command in the program. However, because its call to be implemented by the shell process, the efficiency is not high, and the application is not wide in actual programming. This chapter mainly introduces system calls related to process control and management in actual programming, including:

Fork - Creating a child process Exec - Perform sub-process exit - Termination Process Perform WAIT - Waiting Sub-Process Pause or Terminate SetPGRP - Set Process Identifier GetPID, GetPPID - Get Process Identifier SetUID, SetGID - Set the user identifier GetUID of the process, GetEUID, getGID, getEgID - Get the user identifier of the process

5.2 Process Control

1. Fork system call

The system calling for the system is the only means of creating a new process. It is used to call the newly created process called a child process, calling the process called a parent process. The format of the FORK system call is:

int fork ()

The Fork system call does not have a parameter. If the execution is successful, create a child process, the child process inherits some attributes of the parent process. When returning from the system call, there are all two user-level environments exactly the same process. These two processes are different from the return value obtained in the Fork call, where the sub-process obtained is zero, and the return value obtained by the parent process is the process identifier for the latest sub-process.

2. EXEC system call

The Fork system call is just a copy of the environment of the parent to the new process without launching a new target program. The UNIX system provides an Exec system call, replacing the execution image of the process, start a new target program. For example, all commands in the UNIX system are performed by Exec.

The EXEC system call has six different formats, but only one call entry is called in the core. They have different call formats and call parameters. These six call formats are: #include int execl (const char * path, const char * arg0, ..., const char * argn, (char *) 0); int execv (const char * Path, Char * Const * Argv); int execle (const char * path, const char * arg0, ..., const char * argn, (char * 0), const char * envp []); int execve (Const char * path, char * const * argv, char * const * envp); int execlp (const char * file, const char * arg0, ..., const char * argn, (char *) 0); int Execvp (Const char * File, Char * Const * Argv);

Description: The parameter PATH indicates a path name that can perform the target file; the parameter file indicates the file name of the executable target file. Arg0 as an agreement to point the path name of the target file; parameter arg1 to argnity is the command line parameter in which the target file is executed; the parameter Argv is a string pointer array, which indicates the command line used by the target program. Parameter table, point the same string as the PATH or FILE in accordance with the first character pointer; the last pointer points to an empty string, the rest point to the command line parameters that are performed when the program is executed; the parameter ENVP is also a same as Argv. The character pointer array is pointed out in the process environment when the target program is executed, and it also ends with an empty pointer.

The six formats of Exec differ in the following three points: (1) Path is a full path name of a target file, and file is a target file name, which is searching by environment variable path; (2) by Path Or the command line parameter of the file specified by the file is a complete parameter list or by a pointer array argv; (3) The environment variable is given by the system automatically passes or is given by ENVP.

The following figure illustrates the six different formats of the EXEC system call to the above three points.

System call parameter form Environmental Transmission Path Search EXECL Full list Auto No EXECV Pointer array Auto No Execle Full list Not Auto No EXECVE Pointer Array Not Auto No EXECLP Full list Automatic EXECVP Pointer Array Auto

3. EXIT, WAIT system call (1) Exit system call format is as follows: #include void exit (int status); # include void _exit (int stat (int status); Description: Exit features Terminate the execution of the process and release some of the system resources occupied by the process. The parameter status is the value passed to its parent process when the process is terminated. If the Parent process is waiting to pause or terminate (using the WAIT system call), the parent process can get this value immediately; if the parent process is not waiting in the waiting state, then once the father The process uses Wait calls to get the status value passed by the child process, note: Only the low eight digits of Status is passed to their parent process.

The difference between system call _Exit and Exit is _exit only makes part of the clearance, so it is recommended not to use this invocation form. Each process should call the system call before dying, and the system call is not displayed, the loader generated by the target file is implied to this process. (2) WAIT system call format is as follows: #include #include PID_T WAIT (INT * stat); Description: WAIT system call hangs the call process until the process receives To a signal that is captured or any one of its sub-processes or terminates. If the already sub-process is paused or terminated before the WAIT call, the call is immediately returned. The function of format WAIT ((int *) 0) is to wait for all sub-process to terminate. When Wait returns, its return value is the process number of the sub-process. The value of the parameter statPtr is the term of the sub-process:

1. If the child process is suspended, the status of the statino is stored the signal value of the child process (introduces the signal in Chapter 7), the low eight bit is 01772, if the child process is terminated due to calling EXIT, the value is low Eight bits are 0, the high eight bit is terminated for the child process, the EXIT system calls low eight digits; 3, if the child process is terminated due to signal, the value of the high eight digits is 0, and the low eight bits are the termination. The signal value. In addition, as low as 1, it means a Core file. Let's take an example, this example is an instance program in Fork, Exec, Exit, and Wait, we call Feew.c:

/ * feed.c * / main (argc, argv) int Argc; char * argv []; {INT PID, STAT; if (argc! = 1) {IF ((PID = fork ()) == 0) { Printf ("Child PID =% D / N", getPID ()); Execl (Argv [1], Argv [1], 0); Exit (5);}} PID = Wait (& stat); Printf ("PID) =% D, h_stat =% d, l_stat =% D / N ", PID, STAT >> 8, Stat & 0xFF);

When the number of command line parameters is less than 1, the program uses the Fork system call to generate a child process. The child process has obtained its own process identifier through the system, and then calls the exec executes the command submitted in the command line. If the exec executes fail, the child process calls EXIT (5) termination. The parent process uses the WAIT system call waiting to pause or terminate, then output the information returned from Wait. The procedure is performed in three ways: 1] Do not charge the command line parameter ./feewpid=-1, h_stat = 0, l_stat = 0% does not generate a child process, from the operation result, when there is no child process, Wait The return value is -1.

2] With command line parameters, parameters are legal executable command% ./feew / bin / datechild pid = 1725 February 16, 1998 (Monday) 15:14 14 seconds cstpid = 1725, h_stat = 0, l_stat = 0% generate a child process. After the child process outputs its process identifier, then the exec execute the command (/ bin / date) submitted from the command line, while the parent process is waiting to pause or terminate, then output information obtained from Wait: child process identifier Or the state of the state parameter STAT is high, and the low eight-bit content. It can be seen from it: The child process is terminated by calling an implied exit (0), and the value of the parent process is 0.3] with command line parameters, but the parameter is not legal. / Feew / etc / shudownchIld PID = 1760 / etc / shutdown: Only superusers (root) can run / etc / shutdown. PID = 1760, h_stat = 2, l_stat = 0% child process creation success. However, due to the implementation / etc / shutdown of ordinary users, Exec failed, EXIT (5) was called, and the EXIT (5) was stopped; the parent process called Wait to get the return value: the sub-process number and the state parameter Stat high eight, low eight content. As can be seen from the execution: The child process is terminated by the EXIT (5), and the value of the parent process is 5.

5.3 Process Management

Process management includes a wide range, such as user identifier management, process identifier management, etc. The user identifier of the process has two: actual user identifier (REAL user ID), and the corresponding group identifier is called actual group identifier, respectively, respectively, and a valid group identifier, respectively. Effective GrouDid. In general, the actual user identifier of the process is a user identifier running the process, usually only for system accounting, other functions are completed by a valid user identifier, such as using a valid user identifier to complete the new creation file Attributes, check the access permission of the file and the permission to send a signal to the process using the Kill system call. In general, the effective user identifier and the actual user identifier of a process are equal, but the system allows the change of the effective user identifier.

1. User identifier management UNIX system provides a set of system calls to manage the user identifier of the process, their usage form is: #include #include uid_t getUid (Void) ); uid_t getEuid (void); GID_T getgid (void); GID_T getGID (void); int setuid (uid_t uid); int setgid (GID_T GID); Description: The first four system calls do not have parameters, and return to the actual number of calling processes, respectively User identifier, valid user identifier, actual user group identifier, and valid group identifier. The execution of these system calls is always successful and no errors will occur. The system calls the setuid and setgid to set the actual user (group) identifier of the process and a valid user (group) identifier, such as calling a valid user identifier is a superuser identifier, the actual user of the call will be called (group) The identifier and the valid user (group) identifier are set to the UID or GID; if the valid user identifier of the calling process is not a superuser identifier, but its actual user (group) identifier is equal to the UID or GID, its effective user ( Group) The identifier is set to the UID or GID; otherwise setuid or setgid call failed. The system calls the setuid or setgid call to successfully returns 0, returns -1.2 when failing. Process Identifier Manages UNIX System Using Process Identifiers to manage the process in the current system. In order to manage the process with a similar characteristic, the system introduces the concept of the process group, with the group identifier to distinguish whether the process is the same. The group identifier of the process is inherited from the parent process, so the group identifier of the usual process is the identifier of the registration process associated with it. The identifier of the process is assigned by the system and cannot be modified; the group identifier can be modified via the SetPGRP system.

The format of the related system call is as follows: #include #include pid_t getpid (void); PID_T getpgrp (void); PID_T getpid (void); PID_T getpgID; Description: The first three system calls returned to the process identifier, process group identifier, and its parent process identifier. They always have returned successfully. The fourth call sets process group identifier, which will call the process group identifier to call the process to invoke the process identifier, make it the first process of the process group and return this new process group identifier.

Let's take an example: / * setuid.c * / main (argc, argv) int Argc; char * argv []; {int RET, UID; UID = ATOI (Argv [1]); Printf ("Before Uid =% D, EUID =% D / N ", getuid (), getEuid ()); RET = SetUID (UID); Printf (" After UID =% D, EUID =% D / N ", GetUID (), getEuid ()); Printf ("Ret =% D / N", RET);

The following is discussed in three situations to discuss the execution of the program: 1. If the user executes the program is a super user, the user identifier given by the command line is greater than 0, whether or not the user identifier is present, the total performance is successful. . #. / setuid 3434Before Uid = 0, EUID = 0AFTER UID = 3434, EUID = 3434ret = 0 #

Result Analysis: The actual and valid user identifier of the process is changed to 3434.2. If the user is executed for the user, after the user UID and GID is used by the id command, the process is called, the process is as follows:% iduid = 1111 (YDS) GID = 20%. / SetUID 3434Before UID = 1111, EUID = 1111AFTER UID = 1111, EUID = 1111 Ret = -1%. / Setuid 1111before UID = 1111, EUID = 1111AFTER UID = 1111, EUID = 1111Ret = 0%

Result Analysis: When the command line parameter is 1111, the SetUID is successful because the user's UID is 1111.

It is worth noting that the registration program login is a typical setuid system call program, the valid user of the login process is a super user, which calls setUID to adjust the actual and efficient user identifier to a registered user before the user's shell process. Actual and effective identifiers.

Chapter 6 Equipment Input / Output Control

6.1 Overview

UNIX looks a file as a file, which is a big feature of UNIX. Here you need to introduce a concept of a device number. The equipment special file is related to the two devices - the main device number and the secondary device number. The main device number tells the operating system, which device type will be used when it comes to the file name. For each type of device has a program code that resides in the operating system to control the corresponding type of device, this code is called "device driver". The secondary device number is passed to the device driver, which is used to determine which physical device used. For example, it is determined on a multi-drive control card, which disk drive will be accessed, and which portion of the disk drive will be used; or, when the operation requested by a disk drive is completed, it should be restored. Several devices (such as types of disk drives) can be used with the same master number, but they will have different secondary device numbers. Look at the following example:% ls -l / dev / ttyq * CRW - W ---- 2 YDS USER 15, February 17 09 03 TTYQ1CRW - W ---- 2 YDS USER 15, 14 February 16th at 17:00 TTYQ14%

In the above example, the main device number, 1 and 14 are secondary device numbers. Users can use the system to provide unified and independent of the device's interface - system call to the files to operate the device, and there is no need to involve the specific details of the device. Most of the system calls that operate on documents still work, for example, open the device with Open, read / write the device with read / write, after the device operation is complete, close the device with a Close. But some system calls are different when operated on the device files. If CREATE and OPEN are created, you cannot create device files.

6.2 Equipment Input / Output Control - IOCTL System Call

IOCTL is a system call for device control for device control. This system call is related to device type (ie, host)). Different devices provide different control commands. The call format of IOCTL is: IOCTL (INT FD, INT CMD, Arg ...) Description: Parameter fd is a file description word for a device file, and the CMD is a control command, which is related to the device, and different types of devices have different control commands. The parameter arg does not have a fixed data structure, which is different from CMD.

Chapter 7 Advanced Programming

7.1 Processing signal signal is the most basic communication means between UNIX processes, and the main function is to implement communication between processes. The signal is "soft interrupt" transmitted to the process, which notifies the process that has an abnormal event in their environment. After receiving the signal, the process is handled, the processing mode is one of the following four: (1) default mode (SIG_DFL): This is a general processing method of the process to signal, without special circumstances, after receiving the signal The execution will be terminated. There are some signals that need to be analyzed in the current directory before terminating the process, data segments, data segments, and stack segments to the Core file of the current directory, in order to analyze and use. (2) Ignore the method (SIG_IGN): The process receives a signal that has been ignored, and then the signal is cleared, immediately returns, not at any work. Signal sigkill cannot be ignored. (3) Hold mode (SIG_HOLD): When the process is in this mode, the received signal is saved, and then the process is removed after the process is released. (4) Capture mode (setting signal processing function): This is the signal processing mode of the user setting. When the process receives this signal, execute the signal processing function of the user settings, after execution, restore the site, then continue the execution .

1. There are many types of Unix signals that are commonly used, and some of the most common signals are described below:

SIGHUP hang up. This is the signal sent to the process when the control terminal is suspended. Sigint interrupt. Interrupts generated by the keyboard. Sigquit exits. Interrupts generated by the keyboard. Sigkill terminates. This signal cannot be captured, blocked or ignored. SIGALRM timing signal. SIGTERM software termination signal. SIGUSR1 user-defined signal 1. SIGUSR2 user-defined signal 2. The declaration of these signal values ​​is in the /usr/include/sys/signal.h file.

2. Send Signal-KILL System Call User Transfer Signal to Process System Call is KILL, call format is: #include #include int kill (PID_T PID, INT SIG); Description : This system call sends a signal value of the SIG to the process identifier as the process of PID. Returns 0 when successful, returns -1 when it fails. This call performs success or not, depending on the value of the valid user identifier and the parameter PID of the calling process, the meaning of the PID value is as follows: greater than 0: Send the signal to the process number equal to the process of the PID. Aliquot is equal to 0: Except for the signal sent to the calling process (except 0 and 1 process). Oriented to -1: Send the signal to the actual user identifier equal to all processes (except 0 and 1 process), except for the process of the 0 and 1 process, such as the pay-up process is a super user, then send the signal to 0 and 1 All processes outside the process. Non-1 negative: Send the signal to all processes of the absolute value of the process group identifier for the PID. In actual programming, the Kill system call is very useful, specifically:

· Common way KILL (PID, SIGUSR1) Send signal SIGUSR1 for the process number PID SIGUSR1 · Used to determine if the process exists: if (kill, 0) == 0) The process number is the process of PID; ELSE process number There is no existence for the PID process! · Used to kill the plum process Kill (PID, 1) to kill the process number PID process

2. Processing Signal-Signal System Call User Processing Signal System Call is Signal, call format is: #include void (* Signal (int Sig, Void (* func))) (); Description: The parameter SIG is a signal value, and FUNC defines how the signal is handled. The system defined function is to set the process of processing SIG in the definition of FUNC. When the execution is successful, return the value of the calling process to the signal SIG processing mode, and the failure returns -1. When the parameter is set to the address of SIG_DFL or SIG_IGN or the user signal processing function, the default mode, ignore the method, and the capture method, respectively. 3. Pause system calls the PAUSE system call to the format: pause () Description: This call does not have a parameter, which is functionally to sleep the calling process until it receives a signal. The result of the system call relies on the method of processing the signal to which the process docked.

By default: Termination calling process, PAUSE has no return value; ignore mode: The process is not affected by this signal, continues to sleep; capture mode: After returning from the signal processing function, continue.

4. Using the Signal Time -Alarm System Call System Call ALARM to implement the function of the timer, call the format: #include unsigned alarm (unsigned sec); Description: Parameter sec specifies timing time intervals, in seconds unit. The user process can first call the capture function corresponding to the specified SigalRM signal, and then call ALARM to set the alarm, do your own work during the timing period. The timing time is between, the process receives a SIGALRM signal and executes the capture function corresponding to the signal. System call ALARM is very useful in multi-process programming.

7.2 Piping communication signals to deal with an exception event or an error is very suitable, but it is used to handle a lot of information transfer between the process, it is very unsuitable. To this end, UNIX also provides a mechanism called a pipe, which mainly handles a lot of information transmission between processes. The so-called pipe is a communication channel connected between the processes. It is also a promotion of the concept of UNIX file, and the media of pipe communication is file, called pipeline files. The user can use the system to operate the pipeline file to simplify the design of the pipeline application. The image of the pipeline is described below:

Write Write Reading End READ Pipe is one of the most powerful and most distinctive performance of UNIX, especially at the command line, which allows any command to be connected. E.g:

% WHO | WC -L This command gives the output WHO output to the word count WC through the pipeline, and the option -l tells the WC only calculates the number of lines. The number of users who have been registered through the WC final output.

1. Pipeline programming can create a pipe in the program to call PIPE. If the establishment is successful, two file descriptors are returned, one for writing pipes, one for reading from the pipe. The format of the PIPE call is as follows: int filedes [2], retval; retval = pipe (filedes); where Fildes is an array containing two integers to store two file descriptors identifying the pipe. If the call is successful, FileDes [0] will be opened to read from the pipeline, and Fildes [1] will be opened to write to the pipe.

Once the pipe is established, you can use Read and Write to operate it directly. The true value of the pipeline can be embodied when the pipe is called with the system. At this time, you can use the file that is opened by the parent process, which remains this fact for its sub-process. The following program first creates a pipe, then call the Fork to create a child process, and the parent process sends information through the pipeline to the child process. / * pipe.c * / # include #define msgsize 16char * msg1 = "Hello, World # 1"; char * msg2 = "Hello, World # 2"; char * msg3 = "Hello, world # 3 ";

Main (argc, argv) int Argc; char ** argv; {charinf [msgsize]; int P [2], PID, J;

/ * Open the pipe * / if (PIPE (P) <0) {PERROR ("Pipe Call"); exit (1);} if ((pid = fork ()) <0) {Perror ("fork call") EXIT (2);

/ * Write * / if (PID> 0) {Write (P [1], MSG1, Msgsize); Write (p [1], MSG3, Msgsize); Wait (INT *) 0);

/ * Read * / if (PID == 0) {for (J = 0; J <3; J ) {read (P [0], Inbuf, Msgsize); PrintF ("Child Read) :% s / n ", inbuf);}} exit (0);

The procedure input results are as follows: Child Read: Hello, World # 1child Read: Hello, World # 2child read: Hello, World # 3 Pipes are processed on the basis of advanced first out. Therefore, the data is first placed in the pipeline, and the other end is first read. This order cannot be changed because the system call LSEEK cannot be used for pipelines.

2. Named pipe -fifo We have seen that the pipeline is a strong process communication agency. However, it also has some serious shortcomings. First, the pipe can only be used to connect a process having a common ancestor, such as a connection between the parent child process. This disadvantage is more prominent when you want to develop a program that is always presented, providing a full system range service, such as a network control service program and a printer's spooling program. We ask that the calling process should be able to communicate with any service process with the pipeline, and then disengage it. Unfortunately, ordinary pipes cannot achieve the above functions.

Second, the pipe cannot be standing, and you can establish them when needed, but when accessing their processes, the pipeline is also revoked. So they can't presence forever. In fact, the FIFO mechanism in the UNIX system (also known as named pipe), which makes up for the shortcomings of the above pipelines. The FIFO is the same as the pipeline, but also as a process of advanced first out of the process, but FIFO is a permanent mechanism and has a UNIX file name. FIFO also has file owners, lengths, and access. It can be opened, close and deleted like other UNIX files. But when reading and writing, its performance is the same as the pipeline.

Before discussing the FIFO programming, let's take a look at the FIFO in the command level. UNIX command MKNOD can be used to create a FIFO file Channel:

% / ETC / MKNOD CHANNEL P% LS -L ChannelPRW-R - R - 1 YDS User 0 February 17th 19:00 in the output of the Channel Command LS Points that Channel is a FIFO type file . From China, we can also see its access to read-read, and read only file owners read and write, within the group and other users. Its user is YDS, the group is User, the length is 0, and there are time for file establishment. Most of the FIFO program is mostly the same as the pipeline, the most important difference is in terms of establishment. FIFO is built with MKNOD calls instead of building PIPE. In addition, the eight-input number 010000 must be added to the file mode in the constant S_IFIFO in File /usR/include/Sys/stat.h to indicate that this is a FIFO. Here is an example of establishing FIFO: IF (MkNod ("FIFO", 010600, 0) <0) PERROR ("MkNod (FIFO) Call"; this example establishes a FIFO named FIFO, whose authority is 0600, so This FIFO can be written by its files. Once a FIFO is established, you must use the system to call Open to open it, for example: #include .. fd = Open ("FIFO", O_Wronly);

Implementing an FIFO file is used to write, the following example is used to open the FIFO file in a non-blocking manner for reading: IF ((FD = Open ("FIFO", O_RDONLY | O_DELAY) <0) PERROR ("Open on File "); The following describes two programs, indicating the basic application of FIFO. It is worth noting that both programs constitute the basic framework of FIFO programming, slightly modified, which can be used for FIFO applications in other occasions.

The first is a list of senedfifo.c, used to write strings to the FIFO file:

/ * Sendfifo.c * / # include #include #include #define msgsiz 63extern int errno; main (argc, argv) int Argc; char ** argv; { Int fd; char buf [msgsiz 1]; int I, nwrite;

IF (Argc <2) {fprintf (stderr, "usage: sendfifo msg ...! / n"); exit (1);

IF ((FD = Open ("FIFO", O_Wronly | O_NDELAY)) <0) PRINTF ("FIFO OPEN FAILED!");

For (i = 1; i msgsiz) {fprintf (stderr, "message too long% s! / n", argv [i]); continue;} STRCPY (BUF, Argv [I]);

IF ((NWRITE = Write (FD, BUF, MSGSIZ 1)) <= 0 {if (nwrite == 0) / * full fifo * / errno = eagain; printf ("Message Write Failed!");}} }

Below is a list of profigo.c, and implements read from FIFO:

#include #include #define msgsiz 63main (argc, argv) int Argc; char ** argv; {INT fd; char buf [msgsiz 1]; mknod ("FIFO", 010600 , 0); IF ((FD = Open ("FIFO", O_RDWR)) <0) Printf ("FIFO Open Failed!"); For (;;) {IF (READ (FD, BUF, MSGSIZ 1) < 0) Printf ("Message Read Failed!"); Printf ("FIFO Message Received:% S / N", BUF);}}

The results are as follows:% Recvfifo & [1] 1706% Sendfifo Hello Worldfifo Message Received: Hellofifo Message Received: World%

First, run the Recvfifo program to create a FIFO file "FIFO", and open the file "FIFO" for reading; then, run the sendfifo program to send a string "HelloWorld", write into the file "FIFO".

7.3 IPC Communication Mechanism

1. IPC Overview IPC is a new set of process communication information provided by UNIX system V, which greatly enhances communication functions between processes. The IPC mechanism includes three: messages, semaphors, and shared memory. The program design interface of three IPC agencies is similar, which indicates that their core realization is similar. The most important common feature of IPC is the key, the key is a number of IPC destination in the UNIX system, which is similar to a file name to identify a file. That is, the key can make multiple processes easily shared IPC resources. The target identified by the key can be a message queue, a set of semaphores, or a shared memory segment. The actual data type of the key is determined by the type Key_T implementation, which is defined in the header file /usr/include/sys/types.h.

When an IPC target is established, the system has also established a status structure of an IPC mechanism, which contains management information related to the target. There is a state structure type for message queues, semaphors, and shared memory, each of which must contain only information related to a particular IPC mechanism. However, these three state structural types have related authority structures, this type of authority structure identifies with IPC_Perm, which contains the following:

U_SHORT CUID / * IPC Target Create User ID * / U_SHORT CGID / * Created U_Short UID / * Valid User ID * / U_SHORT GID / * Valid User Group ID * / U_SHORT UMODE / * Permission License * /

This structure determines whether a user can read / write the IPC target. The composition of permissions is exactly the same as the permissions of the file. Therefore, if the value of umode is 0644, it means that the Lord can read and write the corresponding target, while other users can only read. Note that the valid user identifier and a valid group identifier (recorded in the UID and GID) determines the license for access with UMODE. Finally, each form of IPC provides various operational functions so that IPC enrollment can be used. Information queue operation allows messages to send and receive. The semaphore operation allows the amount of signal to increase, decrease, and detect a value. Shared memory operation functions allow processes to add and subtract parts that share the shared memory to their address space.

2. Message queues From essentially, a message is a string character or byte (not necessarily the end of NULL character). The process is transmitted through the message queue between the processes. Establish or access the message queue through the Msgget. Once a message queue is established, as long as access rights are met, the process can put the message into the queue through MSGSND, and another process can read this information with MSGRCV. · MSGGET system calls the msgget call format as follows: #include #include #include int msgget (key_t key, int msgflg);

Description: The parameter key is the key to identify the message queue. If the call is successful, establish a message queue or enable an existing message queue to be accessed. Call Returns an identifier of the message queue. The parameter msgflg determines the action completed by the MSGGet. Two constants can be taken: (1) IPC_CREAT: Create a message queue and will not be rewritten in the case where the message queue already exists. If this flag is not set, the Msgget returns the identifier of the message queue when the queue already exists. (2) IPC_EXCL: If the flag is set to IPC_CREAT, this MSGGET call only wants to establish a message queue. So, when the key value given corresponds to an existing message queue, the call failed and returned -1. When establishing a message queue, the lower 9 bit of MSGFLG is used to write the permissions of the message queue, which is the same as the file mode. Such as: msg_id = msgget ((key_t) 0100, 0644 | IPC_CREAT | IPC_EXCL); this call is a key value (key_t) 0100 creates a message queue. If the call is successful, the privilege of the queue is 0644, which explains the same as file permissions. · MSGGET and MSGRCV system call MSGSND and MSGRCV call formats are as follows:

#include #include #include int msgsnd (int msqid, const void * msgp, size_t msgsz, int msgflg); int MSGRCV (int MSQID) , Void * MSGP, SIZE_T MSGSZ, Long MsgTyp, INTMSGFLG);

Description: Parameter MSQID indicates the queue sent or received by the message, which is obtained by the Msgget call. The structure type of the message is as follows: struct {long mtype; / * message type * / char mText []; / * message body * /}

The programmer can classify the message based on the MTYPE field in this structure. Each possible value of this domain represents a different category. The MTEXT domain is used to store the message body, and the body size can be set by the user.

The system calls MSGSND parameter msgsz specifies the actual length of the send message, and its range can be the maximum length of the message specified from 0 to the system. The parameter MSGSZ in the system calls MSGRCV is specified to give the maximum length of the message can be stored in the structure. If the call is successful, the MSGRCV returns the actual length of the received message.

There is an IPC_nowait in the parameter msgflg in the two system calls. If it is not set, the calling process will enter the sleep state. Otherwise, the call will return immediately.

· MSGCTL system calls MSGCTL call format as follows: #include #include #include int msgctl (int msqid, int cmd, ... / * Struct MSQID_DS * BUF * /); Description: MSGCTL is used to get and modify the properties of a already existing message queue. The parameter msgqid is the ID of the message queue, and the value of the command constant cmd has three: (1) IPC_STAT: Place a backup of the current message of the message queue in the structure. (2) IPC_SET: Sets to control the variable value for the message queue. (3) IPC_rmid: Remove message queues from the system, but only superuser or queue is the master to be implemented.

3. Signal volume (omitted)

4. Shared memory shared memory operation allows two or more processes to share a physical memory segment, which is one of the highest effectiveness in all IPCs. A shared memory segment is described by the unique identifier. · The SHMGET system calls the SHMGET call format is as follows: #include #include #include int shMget (key_t key, size_t size, int shmflg); Description : The parameter key is the key to identify the shared memory. The parameter size is the size of the creation or access to the shared memory. If the call is successful, create a shared memory or enable an existing shared memory to be accessed. The call returns an identifier of the shared memory. The parameter shmflg is called Msgget, the parameter MSGFLG, Semflg in the Semget.

· SHMAT and SHMDT system calls SHMAT and SHMDT call formats are as follows: #include #include #include void * shmat (int shmid, void * shmaddr , int shmflg); int shmdt (void * shmaddr);

Description: The SHMAT call connects the memory segment identified by the parameter SHMID to a valid address of the calling process. The call is successful, and Shmat returns the address Memptr. The parameter shmaddr gives the programmer to call the selected address. The parameter SHMFLG is composed of flag shm_rdonly and shm_rnd. The former request is connected to a read-only, and the latter is used for SHMAT to handle SHMADDR non-0.

The function of SHMDT is just the opposite of Shmat, which implements separating a shared memory segment from the logical address space of the process. This means that the process will no longer use it. · SHMCTL system calls the SHMCLT call format as follows: #include #include #include int shmctl (int shmid, int cmd, ... / * Struct SHMID_DS * BUF * /); Description: This call implements the operation control of shared memory, which is exactly the same as MSGCTL, and its parameter CMD can take IPC_STAT, IPC_SET, and IPC_RMID.

Chapter 8 Network Programming

8.1 Overview

This chapter describes UNIX network programming - ie inter-network process communication. UNIX Internet access is implemented by the Communication Application Interface (API). Currently, the most popular API in the UNIX environment is Berket and UnixSystem V Transmission Layer Interface (TLI). We mainly introduce the socket API. Sockets are divided into supported protocols through the domain, and the currently supported domains are: UNIX domain supports process communication in the UNIX system, the Internet domain supports TCP / IP protocols. The implementation of the socket is attempting to simulate the operation of the process communication with the operational semantic operation of the UNIX file, and its operation is a lot corresponding to the file operation. For example, socket () calls can be approximated as open () calls, call returned file description words as one of the first parameters of other calls; Socket also uses READ and WRITE calls, its syntax and semantic and file operations Read and Write calls almost exactly. Call Bind, Connect, and Accepts in Socket show ways to establish a network connection. As shown in Figure 8-1. Socket Process Communications still uses the Client / Server model, and the work made by Client and Server is asymmetrical when establishing a connection.

8.2 Set of Word Programming Interface Description

Next, an example is combined to illustrate the socket programming interface.

· Socket system call to achieve the allocation of the socket, the modulation format is as follows: #include #include int socket (int domain, int type, int protocol); these: parameters Domain It is a constant, which specifies the area, which is often the AF_INET; the parameter TYPE is a constant, which specifies the type of socket, which can be SOCK_STREAM, SOCK_DGRAM or SOCK_RAW; protocol is a constant, which specifies the protocol used. This parameter is only meaningful when Type is SOCK_RAW, and it is ignored in other cases. This parameter is 0 when selecting the default protocol.

· BIND system call When the application gets the socket, you can contact your own name to your socket using bind () calls, as followed: struct sockaddr_in serveraddress; Memset ((char *) & serveraddress, 0, Sizeof struct sockaddr_in)); serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = inet_addr ( "202.96.6.15"); serverAddress.sin_port = htons (7000); if (bind (sockfd, & serverAddress, sizeof (struct sockaddr_in)) = = -1) {PERROR ("Bind Error"); exit (2);

This code shows that the server program runs in the IP address 202.96.6.15, and the port number is 7000. After Bind call, it is equivalent to publishing his service address. The call format of Bind is as follows: #include #include int bind (int S, const struct sockaddr * name, int namelen);

Where: The parameter S is the file description word returned by the socket call, and the parameter NAME is a pointer to the structural SOCKADDR, and the parameter Namelen specifies the size of the structure. • Listen System Call After the BIND call, the Server program uses the Listen call to prepare to receive a connection from the Client. Listen's call format is as follows: #include #include int Listen (int S, int backlog); where: The parameter S is the file description word returned by the socket call, the parameter backlog designated Maximum number of connections.

• ACCEPT system call After the Listen call, the Server program uses the Accept call to actually receive connection requests from the Client. The call format of Accept is as follows: #include #include int access (int S, struct socketdr * addr, int * addrlen); where: The parameter s is the file returned by the socket call. Description word, parameter addr points to the structure SOCKADDR, which is responsible for reading the corresponding information of the client. Parameters addrlen pointed out the length of the ADDR corresponding structure.

• The Connect system calls in the Client side, after calling the socket, you can initialize a connection request to Server using the Connect call. The following code: struct sockaddr_in serverAddress; memset ((char *) & serverAddress, 0, sizeof (struct sockaddr_in)); serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = inet_addr ( "202.96.6.15"); serverAddress.sin_port = HTONS (7000); if (connect, Sockfd, & ServerAddress, SIZEOF (Struct SockAddr_in)) == - 1) {Perror ("Bind Error"); EXIT (2);} This code is completed to run in IP address 202.96.6.15, the port number is 7000 Server programs to establish a connection. The CONNECT call format is as follows: #include #include int connect (int s, const struct sockaddr * name, int namelen); where: The parameter s is the file returned by the socket call. Description word, parameter NAME is a pointer to the structure SockAddr, and the parameter Namelen specifies the size of the structure.

· Read / Write / Close system call is similar to normal file operation. : EM23:

转载请注明原文地址:https://www.9cbs.com/read-32961.html

New Post(0)