16.2 文件描述符的复制和半关闭
2025/12/30大约 3 分钟
16.2 文件描述符的复制和半关闭
读模式 FILE 和 写模式FILE 是基于同一个fd 创建的,关闭其中任意一个FILE都会导致fd - socket 被关闭。
所以如果要通过fclose 达成半关闭效果首先需要复制fd
这样在关闭写模式FILE时socket 就不会被完全关闭了。
但是这样还是没有实现半关闭,socket 仍然是可读可写的,还是需要通过shutdown 进行半关闭。。。
ps:挺无语的,既然FILE 是根据fd 生成的,那为什么不直接使用shutdown?非要再通过FILE 获取到对应的fd然后再调用shutdown。。。
复制文件描述符
NAME
dup, dup2, dup3 - duplicate a file descriptor
SYNOPSIS
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| oldfd | The dup() system call creates a copy of the file descriptor oldfd, using the lowest-numbered unused descriptor for the new descriptor. | 被复制的文件描述符。返回最小可用的值作为新的文件描述符 | |
| RETURN VALUE | On success, these system calls return the new descriptor. On error, -1 is returned, and errno is set appropriately. | ||
| newfd | it uses the descriptor number specified in newfd. If the descriptor newfd was previously open, it is silently closed before being reused. | 指定新生成的文件描述符编号,如果newfd所指定的文件已经打开那么会关闭该文件。 |
复制出来的newfd 和 oldfd share file offset and file status flags,即它们指向的是同一文件
测试 dup
以只写的方式打开一个文件,然后进行复制,观察newfd 和 oldfd 写入的是否为同一文件;修改file offset 时对另一个是否有影响;newfd能否进行读取
实现:
int main(int argc, char* argv[])
{
int oldfd = open("1.txt", O_WRONLY | O_TRUNC);
if (oldfd == -1)
{
error_handling("open() error");
}
int newfd = dup(oldfd);
if (newfd == -1)
{
error_handling("dup() error");
}
write(newfd, "newfd \n", strlen("newfd \n"));
lseek(newfd, 0, SEEK_SET);
write(oldfd, "old\n", strlen("old\n"));
if(read(newfd, nullptr, 0) == -1)
{
error_handling("read() error");
}
close(oldfd);
close(newfd);
return 0;
}| 行号 | 功能 | 说明 |
|---|---|---|
| 3 | 只写的方式打开1.txt 文件,并清除原有内容 | |
| 9 | 复制 | |
| 15 | 通过复制的fd进行写入 | |
| 17 | 通过newfd 修改file offset | |
| 18 | oldfd 写入 | |
| 20 | 通过newfd 读取文件 |
效果:
ming@ubuntu:/media/sf_share/Network/build$ ./Network
read() error Bad file descriptor
ming@ubuntu:/media/sf_share/Network/build$ cat 1.txt
old
d- 在read时发生错误:Bad file descriptor,说明newfd 和 old share file status flags,都只能写入
- 打印1.txt文件内容:通过newfd 设置file offset为文件起始位置,此时文件内容为newfd \n oldfd 在文件起始位置开始写入
dup2
首先打开一个文件,然后将该文件的fd作为newfd参数传递给dup2,观察newfd指向的文件是否关闭。通过newfd 进行写入,查看写入结果。
实现:
int main(int argc, char* argv[])
{
int newfd = open("1.txt", O_RDONLY);
if (newfd == -1)
error_handling("open() error");
printf("newfd = %d\n", newfd);
int oldfd = 1;
printf("before dup2\n");
sleep(30);
int result = dup2(oldfd, newfd);
printf("after dup2, result = %d\n", result);
write(newfd, "hello world\n", 12);
sleep(30);
return 0;
}效果:
程序输出结果:
newfd = 3
before dup2
after dup2, result = 3
hello worldlsof结果:
dup2 前
Network 2674 ming 2u CHR 136,8 0t0 11 /dev/pts/8
Network 2674 ming 3r REG 0,44 7 73 /media/sf_share/Network/build/1.txt
后
Network 2674 ming 3u CHR 136,8 0t0 11 /dev/pts/8复制文件描述符后 ”流“ 的分离
FILE *readfp = fdopen(clnt_sock, "r");
FILE *writefp = fdopen(clnt_sock, "w");
fputs("Hello World!\n", writefp);
fputs("Welcome to server.\n", writefp);
fflush(writefp);
shutdown(fileno(writefp), SHUT_WR);
fclose(writefp);
fgets(buf, sizeof(buf), readfd);
fputs(buf, stdout);
fclose(readfp);
close(serv_sock);
return 0;