To create a simple pipe with C, we make use of
the pipe() system call. It takes a single argument, which is an array of two
integers, and if successful, the array will contain two new file descriptors
to be used for the pipeline. After creating a pipe, the process typically
spawns a new process (remember the child inherits open file descriptors).
SYSTEM CALL: pipe();
PROTOTYPE: int pipe( int fd[2] );
RETURNS: 0 on success
-1 on error: errno = EMFILE (no free descriptors)
EMFILE (system file table is full)
EFAULT (fd array is not valid)
NOTES: fd[0] is set up for reading, fd[1] is set up for writing
The first integer in the array (element 0) is set up and opened for reading,
while the second integer (element 1) is set up and opened for writing.
Visually speaking, the output of fd1 becomes the input for fd0. Once
again, all data traveling through the pipe moves through the kernel.
If the parent wants to receive data from the child, it should close fd1,
and the child should close fd0. If the parent wants to send data to the
child, it should close fd0, and the child should close fd1. Since
descriptors are shared between the parent and child, we should always be sure
to close the end of pipe we aren't concerned with. On a technical note, the
EOF will never be returned if the unnecessary ends of the pipe are not
explicitly closed.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
main()
{
int fd[2];
pid_t childpid;
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
}
.
.
}
/*****************************************************************************
Excerpt from "Linux Programmer's Guide - Chapter 6"
(C)opyright 1994-1995, Scott Burkett
*****************************************************************************
MODULE: pipe.c
*****************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string)+1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
}
return(0);
}
Often, the descriptors in the child are duplicated onto standard input
or output. The child can then exec() another program, which inherits the
standard streams. Let's look at the dup() system call:
SYSTEM CALL: dup();
PROTOTYPE: int dup( int oldfd );
RETURNS: new descriptor on success
-1 on error: errno = EBADF (oldfd is not a valid descriptor)
EBADF (newfd is out of range)
EMFILE (too many descriptors for the process)
NOTES: the old descriptor is not closed! Both may be used interchangeably
Although the old descriptor and the newly created descriptor can be used
interchangeably, we will typically close one of the standard streams first.
The dup() system call uses the lowest-numbered, unused descriptor for the
new one.
Consider:
.
childpid = fork();
if(childpid == 0)
{
/* Close up standard input of the child */
close(0);
/* Duplicate the input side of pipe to stdin */
dup(fd[0]);
execlp("sort", "sort", NULL);
.
}
Since file descriptor 0 (stdin) was closed, the call to dup() duplicated the
input descriptor of the pipe (fd0) onto its standard input. We then make
a call to execlp(), to overlay the child's text segment (code) with that of
the sort program. Since newly exec'd programs inherit standard streams from
their spawners, it actually inherits the input side of the pipe as its
standard input! Now, anything that the original parent process sends to the
pipe, goes into the sort facility.
There is another system call, dup2(), which can be used as well. This
particular call originated with Version 7 of UNIX, and was carried on through
the BSD releases and is now required by the POSIX standard.
SYSTEM CALL: dup2();
PROTOTYPE: int dup2( int oldfd, int newfd );
RETURNS: new descriptor on success
-1 on error: errno = EBADF (oldfd is not a valid descriptor)
EBADF (newfd is out of range)
EMFILE (too many descriptors for the process)
NOTES: the old descriptor is closed with dup2()!
With this particular call, we have the close operation, and the actual
descriptor duplication, wrapped up in one system call. In addition, it
is guaranteed to be atomic, which essentially means that it will never
be interrupted by an arriving signal. The entire operation will transpire
before returning control to the kernel for signal dispatching. With the
original dup() system call, programmers had to perform a close() operation
before calling it. That resulted in two system calls, with a small degree
of vulnerability in the brief amount of time which elapsed between them.
If a signal arrived during that brief instance, the descriptor duplication
would fail. Of course, dup2() solves this problem for us.
Consider:
.
.
childpid = fork();
if(childpid == 0)
{
/* Close stdin, duplicate the input side of pipe to stdin */
dup2(0, fd[0]);
execlp("sort", "sort", NULL);
.
.
}
分享到:
相关推荐
使用fork(),exec(),dup2(), pipe(),open()系统调用完成与下列shell命令等价的功能:grep -v usr < /etc/passwd | wc -l > result.txt
首先,使用`pipe()`函数创建管道,然后可以使用`dup2()`将管道文件描述符重定向到标准输入输出,以便在Java层通过`System.in`和`System.out`进行读写。 ```cpp #include #include JNIEXPORT void JNICALL ...
在实际应用中,pipe常与其他系统调用(如`fork()`, `dup()`, `exec()`等)结合使用,构建复杂的进程通信网络。了解并熟练掌握pipe,对于进行Linux系统级编程和理解操作系统原理至关重要。通过实践和调试,你可以更好...
- POSIX的`open/read/write/lseek/fcntl/dup` 提供低级文件操作。 4. **文件操作**: - `chown/rename` 改变文件所有者和重命名文件。 - `stat/basename/dirname` 分别获取文件状态、基础名和目录名。 5. **...
Unix课程作业。 使用fork(), exec(), dup2(), pipe() ,open()系统调用完成与下列shell命令等价的功能。 grep –v usr < /etc/passwd | wc –l > result.txt
【计算机Linux实验二应用】主要涉及的是Linux操作系统中的进程通信技术,特别是管道(Pipe)的使用,包括有名管道(FIFO)和无名管道。实验旨在让学习者理解这两种管道的实现原理,并掌握如何在实际编程中运用它们进行...
- dup/dup2:复制文件描述符。 - flock:对文件加锁或解锁。 - truncate/ftruncate:改变文件大小。 - access:检查文件的权限。 - chmod/chown:改变文件权限或所有者。 - stat/statfs:获取文件或文件系统状态。 -...
unix实验基础内容:系统调用assignments assignment 0: Build the linux kernel(20') step 1: get the linux kernel code before you download and compile the linux kernel source, make sure you have ...
│ pipe.c │ read_write.c │ stat.c │ super.c │ truncate.c │ ├─include │ │ a.out.h │ │ const.h │ │ ctype.h │ │ errno.h │ │ fcntl.h │ │ signal.h │ │ stdarg.h │ │ stddef.h │ │ ...
1. 调用`pipe()`函数:这会在内存中创建一个匿名管道,并返回两个文件描述符,一个用于读取(fd[0]),另一个用于写入(fd[1])。 2. 创建子进程:通常使用`fork()`函数创建子进程。父进程和子进程共享创建的管道。...
例如,在C++中,可以使用`_pipe`函数创建管道,`dup2`函数重定向标准输入/输出,`fork`创建子进程,然后在父子进程中使用`read`和`write`函数进行数据交换。 管道在实际应用中广泛用于各种场景,比如进程间的日志...
为了将数据流导向管道,我们可以使用`dup2()`函数来替换进程的标准输入(0)、输出(1)或错误输出(2)。例如,子进程可以将`fd[1]`作为其标准输出,以便将数据写入管道。 ```c dup2(fd[1], 1); // 将fd[1](写端...
通常,Linux提供了如`pipe`函数来创建单向管道,但这种管道只能实现一个方向的数据传输。例如,`popen`和`pclose`函数可以创建一个简单的命令执行管道,但它们仅支持单向流,即要么只能写入,要么只能读出,不能同时...
- **函数原型**:`int pipe(int fd[2]);` - **功能**:创建一个无名管道,即一种特殊的文件,它存在于内存中,并且只在父子进程间通信时使用。 - **参数**:`fd` 是一个包含两个元素的数组,`fd[0]` 用来读取管道,`...
这个主题主要涉及到如何在C++中创建和管理进程,并且通过管道(pipe)实现父进程与子进程之间的数据传输,使得父进程能够向子进程发送命令,进而让子进程执行相应的操作。以下是对这个主题的详细阐述: 首先,我们...
旧版本版本的全志R16平台的tinav2.1的系统打开softAP 2017/9/14 17:25 版本:V1.0 1、原始编译: ...rootroot@cm-System-Product-Name:~$ cd /home/wwt/ ...rootroot@cm-System-Product-Name:/home/wwt$ tar zxvf...
dup2(pipe_fd[1], 1); // 将管道写端设为标准输出 close(pipe_fd[0]); // 关闭管道读端 execlp("ls", "ls", NULL); } else { // 父进程 dup2(pipe_fd[0], 0); // 将管道读端设为标准输入 close(pipe_fd[1]); /...
由于Android环境中不支持`dup2`函数,这里将相关代码注释掉,避免编译错误。 - **修改 src/boa.c** ```c #if 0 if (passwdbuf == NULL){ DIE("getpwuid"); } if (initgroups(passwdbuf->pw_name, passwdbuf-...
- `dup()`, `dup2()`: 复制或重定向文件描述符。 - `ioctl()`: 对I/O设备进行控制操作。 3. **网络编程**: - `socket()`: 创建套接字,是网络通信的基础。 - `bind()`, `listen()`, `accept()`: 绑定地址,...
通过`pipe()`函数创建管道,然后使用`fork()`创建子进程,`dup2()`重定向标准输入输出,`execlp()`替换当前进程执行新的命令。例如,使用管道连接`grep`和`ps`命令,筛选出包含"sh"的进程: ```c int main() { int...