Server program specification
- Linux server programs generally run as background processes (daemons). It does not control the terminal, so it will not accidentally receive user input. The parent process of the daemon is usually the init process (PID 1).
- A professional log system is required for the debugging and maintenance of the server. Linux often uses a daemon rsyslogd (upgraded version of syslogd) to process system logs.
- Linux server programs generally run as non root. For example, background processes such as mysqld, httpd and syslogd have their own running accounts mysql, apache and syslog respectively.
- Linux server programs can usually handle many command-line options. If there are too many options to run at one time, they can be managed by configuration files. The configuration file is generally placed in the / etc directory.
- Linux server programs usually generate a file recording the PID of the background process at startup and store it in the / var/run directory. For example, the PID file of syslogd is / var/run/syslogd.pid.
journal
rsyslogd daemon
Both user process output logs and kernel logs can be accepted.
- The user process calls the syslog function to output the log to a UNIX local domain socket type (AF_UNIX) file / dev/log, and rsyslogd listens to the file to obtain the output of the user process.
- The kernel log is printed to the ring buffer of the kernel by functions such as printk. The contents of the ring buffer are directly mapped to / proc/kmsg. rsyslogd reads the file to obtain the kernel log.
syslog function
The application communicates with the rsyslogd daemon through the syslog function:
#include<syslog.h> void syslog( int priority, const char* message, ...); // The output is structured with variable parameters (message and the third parameter...) // priority: the bitwise or between the facility value and the log level. The default value of the facility value is LOG_USER.
Limited to log_ The log levels corresponding to the user facility value are:
#include<syslog.h> #define LOG_ Emerg 0 / / system unavailable #define LOG_ Alert 1 / / an alarm requires immediate action #define LOG_ Crit 2 / / very serious condition #define LOG_ Err 3 / / error #define LOG_ Warning 4 / / warning #define LOG_ Note 5 / / notification #define LOG_ Info 6 / / Info #define LOG_ Debug 7 / / debugging
openlog function
Change the default output mode of syslog to further structure the log content:
#include<syslog.h> void openlog( const char* ident, int logopt, int facility ); // The string specified by ident is usually set to the name of the program after it is added to the date and time of the log message // logopt configures the behavior of syslog calls as bitwise OR bitwise of the following values: #define LOG_ PID 0x01 / / in the log message, the boahan program PID #define LOG_ Cons 0x02 / / if the message cannot be recorded in the log file, it will be printed to the terminal #define LOG_ Odelay 0x04 / / delay opening the log function until syslog is called for the first time #define LOG_ NDELAY 0x08 / / enable logging without delay // Facility is used to modify the default facility value in the syslog function
setlogmask function
The program may need to output a lot of debugging information in the development stage, and these debugging information needs to be closed after release.
The way to solve this problem is not to delete the debugging code after release (it may be needed in the future), but to set the log mask so that the log information with a log level greater than the mask is ignored by the system.
The setlogmask function is used to set the log mask:
#include<syslog.h> int setlogmask( int maskpri ); // maskpri specifies the log mask value // This function always succeeds, returning the old log mask value of the calling process
closelog function
To turn off logging:
#include<syslog.h> void closelog();
user
Different users in the server have different permissions, so it is particularly important to obtain or set the real user ID (UID), valid user ID (EUID), real group ID (GID) and valid group (EGID) of the current process:
#include <sys/types.h> #include <unistd.h> uid_t getuid(); uid_t geteuid(); gid_t getgid(); gid_t getegid(); int setuid( uid_t uid ); int seteuid( uid_t uid ); int setgid( gid_t gid ); int setegid( gid_t gid );
A process has two user ID s: UID and EUID. EUID facilitates resource access: the user running the program has the permissions of a valid user of the program. For example, any user can modify his account information through the su program, so he has to access the / etc/passwd file requiring root permission. So how can an su program started as an ordinary user access the / etc/passwd file?
It can be seen from the ls command that the owner of the su program is root and the set user ID flag is set, that is, when any ordinary user runs the su program, the valid user of the su program is root. Processes with root as the valid user are called privileged processes.
Similarly, EGID provides valid group permissions for group users running the target program.
Relationship between processes
Process group
Under Linux, each process belongs to a process group, and PGID is its process group ID. The process group will always exist until all processes in it exit or join other thread groups. Each process group has a leader process with the same PGID and PID.
#include< unistd.h> pid_t getpgid( pid_t pid ); // ID is returned successfully, and - 1 is returned in case of failure, and errno is set int setpgid( pid_t pid, pid_t pgid ); // Set the pgid of the process with PID as pgid. If PID and pgid are equal, the process specified by PID will be set as the process group leader // If pid=0, the pgid of the current process is set to pgid // If pgid=0, pid is used as the PGID of the target process // It returns 0 on success, returns - 1 on failure, and sets errno
A process can only set its own or child process's PGID. After the child process calls the exec series functions, the parent process can no longer set its PGID.
conversation
Some associated process groups can form a session. The following function is used to create a session:
#include<unistd.h> pid_t setsid( void ); // The PGID of the new process group is returned on success. If it fails, it returns - 1 and sets errno
This function cannot be called by the leader process of the process group, otherwise an error will be generated. For processes that are not group leaders, creating a new session has the following additional effects:
- The calling process becomes the leader of the session, and the process is the only member of the new session.
- Create a new process group, whose PGID is the PID of the calling process, and the calling process becomes the leader of the group.
- The calling process will throw away the terminal (if any).
The Linux process does not provide the concept of session ID (SID), but regards the PGID of the process group where the session leader is located as a SID, and provides the following functions to read the SID:
#include<unistd.h> pid_t getsid( pid_t pid );
System resource limitation
Programs running on Linux will be affected by resource constraints, such as physical device restrictions (number of CPUs, memory, etc.), system policy restrictions (CPU time, etc.), and specific implementation restrictions (maximum length of file name). These system resource limits can be read and set through the following functions:
#include <sys/resource.h> int getrlimit( int resource, struct rlimit* rlim ); int setrlimit( int resource, const struct rlimit* rlim ); // Return 0 on success, return - 1 on failure and set errno. struct rlimit{ rlim_t rlim_cur; // The soft limit of specified resources is a recommended limit. It is best not to exceed the limit. If the limit is exceeded, the system may send a signal to the process to terminate its operation. rlim_t rlim_max; // Specifies the hard limit of resources, usually the upper limit of soft limit. Ordinary programs can reduce the hard limit, and only programs running as root can increase the hard limit. // rlim_t is an integer type that describes the resource level. };
In addition to the above:
- You can also use the ulimit command to modify the resource limit (soft limit or / and hard limit) in the current shell environment. This modification will be effective for all subsequent programs started by the shell.
- You can also change the system soft and hard limits by modifying the configuration file, which is permanent.
Change working directory and root directory
#include<unistd.h> /* Gets the current working directory of the process */ char* getcwd( char* buf, size_t size ); // The memory pointed to by buf is used to store the absolute pathname of the current working directory of the process, and the size is specified by the size parameter // If the absolute path length of the current work (plus "\ 0" at the end) exceeds size, NULL is returned and errno is set to ERANGE. // If buf is NULL and the size is not 0, getcwd may dynamically allocate memory internally using malloc and store the current working directory of the process in it, // At this point, we need to release the memory created internally by getcwd. // Successfully return a pointer to the target storage area (the cache area pointed to by buf or the cache area dynamically created by getcwd internally). If failed, return NULL and set errno. /* Change the working directory of the process */ int chdir( const char* path ); // path specifies the target directory to switch to // 0 is returned for success, - 1 is returned for failure, and errno is set /* Change process root directory */ int chroot(const char* path); // The parameters and return values are the same as above. After calling this function, you still need to use chdir("/") to switch the working directory to the new root directory. // After changing the root directory of the process, the program may not be able to access the file or directory in the old path, // However, you can use the file descriptor that the process has opened to access files that cannot be accessed directly after calling chroot. // Only privileged processes can change the root directory
Server program postprocessing
Let a process run as a daemon:
#include<unistd.h> int daemon(int nochdir, int noclose); // nochdir is used to specify whether to change the working directory. If it is 0, the working directory will be set to "/ (root directory). Otherwise, continue to use the current directory // When noclose is 0, the standard input, output and error output are redirected to the / dev/null file. Otherwise, the original device is still used // 0 is returned for success, - 1 is returned for failure, and errno is set