The role of DUP and dup2

Source: Internet
Author: User
Tags printf socket stdin
the role of DUP and dup2DUP and dup2 are also two very useful calls that are used to copy the descriptor of a file. They are often used to redirect stdin, stdout, and stderr of processes. The prototypes for these two functions are as follows:
#include
int dup (int oldfd);
int dup2 (int oldfd, int targetfd)
With the function DUP, we can copy a descriptor. Passed to the function an existing descriptor, it will return a new descriptor, the new descriptor is a copy of the descriptor passed to it. This means that both descriptors share the same
[url=http://www.pcdog.com/special/1002/index.html] data structure [/url]
。 For example, if we perform a lseek operation on a file descriptor, the location of the first file is the same as the second one. Here is a snippet of code to illustrate how the DUP function is used:
int fd1, FD2;
...
FD2 = DUP (FD1);
It is important to note that we can create a descriptor before calling fork, which is the same as invoking the DUP to create a descriptor, and the child process will also receive a copy of the descriptor.

The DUP2 function is similar to the DUP function, but the DUP2 function allows the caller to specify the ID of a valid descriptor and a target descriptor. When the DUP2 function returns successfully, the target descriptor (the DUP2 function
Two parameters) will become a copy of the source descriptor (the first parameter of the DUP2 function), in other words, two file descriptors now point to the same file, and is the file to which the function's first argument points. Below
We use a piece of code to illustrate:
int OLDFD;
OLDFD = open ("App_log", (O_rdwr | o_create), 0644);
Dup2 (OLDFD, 1);
Close (OLDFD);

In this example, we open a new file called "App_log" and receive a file descriptor called FD1. We call the DUP2 function with the arguments OLDFD and 1, which
Causes the file descriptor represented by 1 to be replaced with our newly opened file descriptor (that is, stdout, because the standard output file has an ID of 1). Anything written to StdOut will now be changed to write
into a file named "App_log". It is important to note that the DUP2 function closes the OLDFD immediately after it has been copied, but does not turn off the newly opened file descriptor because the file description
The character 1 now also points to it.
Let's introduce a more in-depth example code. Recall the command line pipeline described earlier in this article, where we connect the standard output of the ls–1 command to the WC–L command as standard input. Next, we will use a C program to illustrate the implementation of this process. The code is shown in example code 3 below.

In example code 3, you first establish a pipeline in line 9th, and then divide the application into two processes: a subprocess (line 13–16) and a parent process (line 20–23). Next
First close the STDOUT descriptor (line 13th) in the subprocess, and then provide the LS
The –1 command function, but it is not written to stdout (line 13th), but instead writes to the input of the pipeline we have established, which is done via the DUP function to redirect. On line 14th, use dup2
The function redirects the stdout to the pipe (pfds[1]). After that, turn off the input of the pipe immediately. Then, replace the image of the process with the command LS using the EXECLP function
–1 process image, and once the command executes, any output of it will be sent to the input side of the pipeline.

Now let's look at the receiving end of the pipe. As you can see from the code, the receiving side of the pipeline is assumed by the parent process. First, close the stdin descriptor (line 20th), as we will not go from the machine's keyboard
Device file to receive input from the data, but to receive data from the output of other programs. Then, once again, using the DUP2 function (line 21st), let the stdin become the output of the pipeline, which is achieved by allowing the text
Descriptor 0 (that is, regular stdin) equals pfds[0]. Close the stdout end of the pipe (pfds[1]) because it is not available here. Finally, use
The EXECLP function replaces the image of the parent process with the process image of the command wc-1, and the command wc-1 takes the contents of the pipeline as its input (line 23rd).
Example code 3: code that implements pipelined operations of the command with C
1: #include
2: #include
3: #include
4:
5:int Main ()
6: ... {
7:int pfds[2];
8:
9:if (pipe (PFDS) = = 0) ... {
10:
11:if (fork () = = 0) ... {
12:
13:close (1);
14:dup2 (Pfds[1], 1);
15:close (Pfds[0]);
16:EXECLP ("ls", "ls", "-1", NULL);
17:
:} else ... {
19:
20:close (0);
21:dup2 (Pfds[0], 0);
22:close (Pfds[1]);
23:EXECLP ("WC", "WC", "-l", NULL);
24:
25:}
26:
27:}
28:
29:return 0;
30:}
In this program, it is particularly interesting that our child process redirects its output to the input of the pipeline, and then the parent process redirects its input to the output of the pipeline. This is a very useful technique in real-world application development.
1. File descriptor in the kernel data structure
Before I go into specific dup/dup2, I think it's necessary to look at the file descriptor's pattern in the kernel.
During this existence of a process, some files are opened, which returns some file descriptors from the shell
The default is 3 file descriptors (0, 1, 2), 0 is associated with the standard input of a process,
1 is associated with the standard output of the process, 2 is associated with the standard error output of the process, and what is currently open for a process
The file descriptor can be viewed through the/proc/process id/fd directory. The following figure illustrates the problem clearly:
Process Table Entry
————————————————
FD Flag File pointer
_____________________
FD 0:|________|____________|------------> File Table
FD 1:|________|____________|
FD 2:|________|____________|
FD 3:|________|____________|
| .......         |
|_____________________|
Figure 1
       
File table contains: File status flag, current file offset, v node pointer, these are not discussed in this article
Focus, we just need to know that each open file descriptor (FD flag) has its own file table in the process table
Item, which is pointed to by the file pointer.
2. dup/dup2 function
Both the Apue and man documents have a concise statement of what these two functions do: Copying an existing file descriptor.
#include
int dup (int oldfd);
int dup2 (int oldfd, int newfd);
Analyzing this process from the diagram, when the DUP function is called, the kernel creates a new file descriptor in the process, which
Descriptor is the smallest value of the currently available file descriptor, which points to a file table entry owned by OLDFD.
Process Table Entry
————————————————
FD Flag File pointer
_____________________
FD 0:|________|____________| ______
FD 1:|________|____________|----------------> | |
FD 2:|________|____________| | File Table |
FD 3:|________|____________|----------------> |______|
| .......         |
|_____________________|
Figure 2: Schematic diagram after invoking the DUP
As shown in Figure 2, if the value of OLDFD is 1, the minimum value of the current file descriptor is 3, then the new descriptor 3 points to
The file table entry owned by descriptor 1.
The difference between dup2 and DUP is that the value of the new descriptor can be specified with the NEWFD parameter, and if NEWFD is already open, the
Turn it off first. If NEWFD equals OLDFD, DUP2 returns NEWFD without closing it. The DUP2 function returns a new
The file descriptor also shares the same file table entry as the parameter OLDFD.
Apue illustrates this problem in a different way:
In fact, invoke the DUP (OLDFD);
Equivalent to
Fcntl (OLDFD, F_DUPFD, 0)
and call Dup2 (OLDFD, NEWFD);
Equivalent to
Close (OLDFD);
Fcntl (OLDFD, F_DUPFD, NEWFD);
3. Dup2 in CGI
Anyone who has written a CGI program knows that when the browser submits the form data using the Post method, the CGI read data is from the standard
Input stdin, write data is written to the standard output stdout (C language using the printf function). According to our normal management
Solution, the output of printf should be displayed in the terminal, the original CGI program using the DUP2 function will Stdout_finleno (this
The macro is defined in Unitstd.h, which is 1) This file descriptor is redirected to a connection socket.
Dup2 (CONNFD, Stdout_fileno);/* The actual situation also involves the pipeline, not the focus of this article * *
As mentioned in the first section, a process default file descriptor 1 (stdout_fileno) is the standard output STDOUT phase
For the kernel, all open files are referenced by a file descriptor, and the kernel does not know the
exist (such as stdin, stdout), so the data that the printf function outputs to stdout is finally written in the file description
Character 1 inside. As for file descriptors 0, 1, 2 are associated with standard input, standard output, standard error output, which
It's just the practice of the shell and many applications, not the kernel.
Use the flow graph below to illustrate the problem: (PS: Not a flow graph relationship, but it helps to understand)
Terminal (TTY), Stdout_fileno (1), stdout, printf
printf final output to the terminal equipment, file descriptor 1 pointing to the current terminal can be understood as follows:
Stdout_fileno = open ("/dev/tty", O_RDWR);
After using dup2 Stdout_fileno no longer points to the end device, but to CONNFD, so printf's
The output is finally written to the CONNFD. is not very beautiful. :)
4. How to restore Stdout_fileno in the fork sub-process of a CGI program
If you can see here, thank you for your patience, I know a lot of people may feel a little complicated, in fact
A complex problem is a collection of small problems. So make sure every little problem is OK, in the third section
said that Stdout_fileno was redirected to the CONNFD socket, and sometimes we might want to be in a CGI program
And there are some input and output in these scripts, and we know that after the fork,
The child process inherits all the file descriptors of the parent process, so the input and output of these scripts will not be as we wish
Output to the end device, but with CONNFD want to associate, this will obviously disturb the output of the Web page. So how
Restore Stdout_fileno and terminal associations.
Method 1: Save the original file descriptor before dup2, and then restore.
The code is implemented as follows:
SAVEFD = DUP (Stdout_fileno); /*SAVEFD point to terminal at this point */
Dup2 (CONNFD, Stdout_fileno); /*stdout_fileno (1) was re-directed to connfd*/
..../* Handle some things */
Dup2 (SAVEFD, Stdout_fileno); /*stdout_fileno (1) restore point to savefd*/
Unfortunately, CGI programs cannot use this method because dup2 is not done in CGI programs, but in
Implemented in Web server, modifying Web server is not a good idea.
Method 2: Trace, open the current terminal recovery Stdout_fileno.
Analyze the flow graph in section Three, how Stdout_fileno is associated with the terminal. We'll do it all over again.
, the code is implemented as follows:
TTYFD = open ("/dev/tty", O_RDWR);
Dup2 (TTYFD, Stdout_fileno);
Close (TTYFD);
/dev/tty is the terminal where the program is running, which should be obtained through a method. Practice proves that this method
is feasible, but I always feel something is wrong, do not know why, perhaps some potential problems have not appeared.
At present I think of both methods, do not know what you have a good idea. Some words want to tell me:)




[B] This article from the Chinaunix blog, if you see the original point: [/b][url]http://blog.chinaunix.net/u/6889/showart_448276.html[/url]

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.