Linux socket编程(8):shutdown和close的区别详解及例子

13 篇文章 5 订阅
订阅专栏
本文详细介绍了Linux系统中close和shutdown函数在终止socket进程通信中的不同行为,包括close关闭连接并释放资源,shutdown用于控制数据传输方向。通过实例演示了shutdown在实际场景中的使用,如客户端在接收EOF后关闭写方向等待服务端响应。
摘要由CSDN通过智能技术生成

在Linux中有两种操作可以终止socket间的进程通信:closeshutdown。但这两种函数在使用时有着不同的行为和效果。在网络编程中,正确地选择和使用这些操作至关重要,因为它们直接影响着通信的结束和资源的释放。本文将介绍closeshutdown函数,然后举一个实际的例子来说明shutdown的使用。

1 close

close函数将终止一个套接字的连接(如果已连接上),然后关闭文件描述符,释放相关的资源。close将关闭数据传输的两个方向,之后进程将无法读/写入套接字。

int close(int sockfd);
  • 参数:
    • sockfd:套接字文件描述符。
  • 返回值:
    • 成功:0
    • 失败:-1,错误号存储于errno中。

注意,close只是将套接字引用计数减一,当引用计数变为零时,真正关闭套接字

  1. 套接字引用计数: 在Linux中,每个打开的套接字都有一个引用计数。引用计数跟踪着对套接字的引用次数,即有多少个文件描述符指向同一个套接字。
  2. close 函数的作用: 当调用close函数关闭一个套接字时,实际上只是将套接字的引用计数减一。这意味着释放了一个对套接字的引用,但套接字仍然存在。

这种机制允许多个进程或线程共享同一个套接字,这个在 利用fork实现服务端与多个客户端建立连接中有出现过,使用fork创建子进程的时候,父进程的上下文被拷贝,所以在子进程中的一开始就要close父进程的socket,否则父进程close自身套接字时,套接字并不能真正的被回收。

2 shutdown

shutdown函数用于关闭一个已连接的套接字或禁止在套接字上的发送或接收数据。该函数可以在全双工(TCP)套接字上单独关闭读取或写入,也可以同时关闭两者。

int shutdown(int sockfd, int how);
  • 参数:
    • sockfd:套接字文件描述符。
    • how:关闭方式,可以取值为:
      • SHUT_RD:关闭读取
      • SHUT_WR:关闭写入
      • SHUT_RDWR:同时关闭读取和写入
  • 返回值:
    • 成功:0
    • 失败:-1,错误号存储于 errno 中。

3 实例:shutdown的使用

参考代码上一节的代码 IO复用模型之select原理及例子:客户端接收stdin的输入然后发给服务端,服务端收到这个消息后再回显给客户端。

3.1 代码修改

目的:在客户端发送消息给服务端后,等待服务端返回回显数据后,客户端就退出程序。

1、客户端

首先我们希望在标准输入收到EOF时,客户端关闭写方向和标准输入的接收,等待服务端的最后一次回复,收到后打印出来。

在这里插入图片描述

2、服务端

服务端在收到消息后,延时5s,此时在客户端输入EOF,这时客户端关闭掉了写方向。等到延时结束后看看send的回显能不能被客户端收到。

在这里插入图片描述

3.2 实验结果

在这里插入图片描述

这样就实现了客户端发送最后一个消息后,等待服务端回复完后就自动退出程序。

3.3 完整代码

服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define MAX_CLIENTS 10
#define BUFFER_SIZE 1024

int main() {
    int serverSocket, clientSockets[MAX_CLIENTS], maxSockets, activity, i, valread;
    int opt = 1;
    struct sockaddr_in address;
    fd_set readfds;
    char buffer[BUFFER_SIZE];

    // Create server socket
    if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    // Set socket options
    if (setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("Setsockopt failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8888);

    // Bind the socket
    if (bind(serverSocket, (struct sockaddr*)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    // Listen for incoming connections
    if (listen(serverSocket, MAX_CLIENTS) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }

    printf("Server listening on port 8888\n");

    maxSockets = serverSocket;
    memset(clientSockets, 0, sizeof(clientSockets));

    while (1) {
        FD_ZERO(&readfds);
        FD_SET(serverSocket, &readfds);

        for (i = 0; i < MAX_CLIENTS; i++) {
            int clientSocket = clientSockets[i];
            if (clientSocket > 0) {
                FD_SET(clientSocket, &readfds);
                if (clientSocket > maxSockets) {
                    maxSockets = clientSocket;
                }
            }
        }

        activity = select(maxSockets + 1, &readfds, NULL, NULL, NULL);

        if (FD_ISSET(serverSocket, &readfds)) {
            // Handle new connection
            int newSocket;
            socklen_t addrlen = sizeof(address);
            if ((newSocket = accept(serverSocket, (struct sockaddr*)&address, &addrlen)) < 0) {
                perror("Accept failed");
                exit(EXIT_FAILURE);
            }

            printf("New connection, socket fd is %d, ip is : %s, port : %d\n", newSocket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));

            for (i = 0; i < MAX_CLIENTS; i++) {
                if (clientSockets[i] == 0) {
                    clientSockets[i] = newSocket;
                    break;
                }
            }
        }

        for (i = 0; i < MAX_CLIENTS; i++) {
            int clientSocket = clientSockets[i];
            if (FD_ISSET(clientSocket, &readfds)) {
                // Handle data from client
                valread = read(clientSocket, buffer, BUFFER_SIZE);
                if (valread == 0) {
                    // Client disconnected
                    printf("Host disconnected, socket fd is %d\n", clientSocket);
                    close(clientSocket);
                    clientSockets[i] = 0;
                } else {
                    // Echo received message back to client
                    buffer[valread] = '\0';
                    printf("Received: %s", buffer);
					sleep(5);
					printf("sleep over\n");
                    send(clientSocket, buffer, strlen(buffer), 0);
                }
            }
        }
    }

    return 0;
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUFFER_SIZE 1024

int main() {
    int clientSocket;
    struct sockaddr_in serverAddress;
    fd_set readfds;
    char buffer[BUFFER_SIZE];

    // Create client socket
    if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(8888);
	serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");

    // Connect to server
    if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) {
        perror("Connection Failed");
        exit(EXIT_FAILURE);
    }

    printf("Connected to server\n");
	int stdinOn = 1;
    while (1) {
        FD_ZERO(&readfds);
		if(stdinOn)
	        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(clientSocket, &readfds);

        select(clientSocket + 1, &readfds, NULL, NULL, NULL);

        if (FD_ISSET(STDIN_FILENO, &readfds)) {
            // Read from stdin and send to server
            if(fgets(buffer, BUFFER_SIZE, stdin) == NULL)
			{
				printf("shutdown\n");
				shutdown(clientSocket, SHUT_WR);
				stdinOn = 0;
			}else
			{
				send(clientSocket, buffer, strlen(buffer), 0);
			}
        }

        if (FD_ISSET(clientSocket, &readfds)) {
            // Read from server and print
            memset(buffer, 0, sizeof(buffer));
            int len = recv(clientSocket, buffer, BUFFER_SIZE, 0);
			if(len == 0)
			{
				printf("server close\n");
				break;
			}
            printf("Server: %s", buffer);
        }
    }

    return 0;
}
tcp网络closeshutdown区别
SteveForever的博客
07-27 327
关闭范围close: 完全关闭套接字,即不能再发送或接收数据。shutdown: 可以选择性地关闭套接字的读、写或读写方向。用途close: 适用于需要完全终止连接的情况。shutdown: 适用于需要部分终止连接的情况,例如停止发送但仍需要接收数据。系统级行为close: 关闭文件描述符并减少引用计数。shutdown: 不影响文件描述符,只影响套接字的通信方向。触发的TCP行为close: 触发TCP的四次挥手过程,优雅地终止连接。shutdown: 可能触发FIN包的发送(在。
深入理解linuxcloseshutdown区别
09-15
以下是对linuxcloseshutdown区别进行了详细的分析介绍,需要的朋友可以过来参考下
shutdown 函数和 close函数的区别
最新发布
yuanbenshidiaos的博客
08-16 1011
网络编程中,shutdown允许你精细地控制连接的关闭过程,而close用于完全关闭套接字并释放资源。在文件操作中,close用于关闭文件并释放文件描述符。正确使用这些函数对于资源管理和程序的正确行为至关重要。
linuxsocketcloseshutdown
08-05 2万+
Linux socket关闭连接的方法有两种分别是shutdownclose,首先看一下shutdown的定义 #include int shutdown(int sockfd,int how); how的方式有三种分别是 SHUT_RD(0):关闭sockfd上的
linux网络编程之shutdown() 与 close()函数详解
热门推荐
lgp88的专栏
01-05 4万+
1.close()函数 #include int close(int sockfd); //返回成功为0,出错为-1.     close 一个套接字的默认行为是把套接字标记为已关闭,然后立即返回到调用进程,该套接字描述符不能再由调用进程使用,也就是说它不能再作为read或write的第一个参数,然而TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终
linux网络编程--shut_down和close()函数的区别
鱼思故渊的专栏
09-01 5396
Linux C网络编程中,一共有两种方法来关闭一个已经连接好的网络通信,它们就是close函数和shutdown函数,它们的函数原型分别为: 1 #include 2 int close(int sockfd) 3 //返回:0——成功, 1——失败 4
高性能网络编程4--TCP连接的关闭
iteye_10227的博客
10-26 1776
TCP连接的关闭有两个方法closeshutdown,这篇文章将尽量精简的说明它们分别做了些什么。 为方便阅读,我们可以带着以下5个问题来阅读本文: 1、当socket被多进程或者多线程共享时,关闭连接时有何区别? 2、关连接时,若连接上有来自对端的还未处理的消息,会怎么处理? 3、关连接时,若连接上有本进程待发送却未来得及发送出的消息,又会怎么处理? 4、so_linger这个功能的用处在哪?...
linuxclose函数和,linux网络编程之shutdown() 与 close()函数详解
weixin_31714129的博客
05-03 1675
1.close()函数#includeint close(int sockfd); //返回成功为0,出错为-1.作用:close一个套接字的默认行为是把套接字标记为已关闭,然后立即返回到调用进程。该套接字描述符不能再由调用进程使用,也就是说它不能再作为read或write的第一个参数。要注意TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终止序列。在多进...
linux网络编程之socket(十):shutdownclose 函数 的区别
Meditation
06-10 2万+
假设server和client 已经建立了连接,server调用了close, 发送FIN 段给client(其实不一定会发送FIN段,后面再说),此时server不能再通过socket发送和接收数据,此时client调用read,如果接收到FIN 段会返回0,但client此时还是可以write 给server的,write调用只负责把数据交给TCP发送缓冲区就可以成功返回了,所以不会出错,而s
Linuxsocket编程详解
02-07
### LinuxSocket编程详解 #### 一、网络中进程间通信机制 进程间通信(IPC, Inter-Process Communication)在单机系统中主要是通过管道、信号、消息队列等方式实现的。然而,当涉及到跨主机通信时,就需要解决...
【C语言】Linux socket 编程
数字人生
01-03 1700
在 TCP 连接中,`close()` 函数的执行将启动 TCP 连接的终止过程,通常称为四次挥手(four-way handshake)。函数在 Socket 编程中用于将一个未连接的 socket 转换成一个被动的监听 socket,指示内核应当接受指向该 socket 的连接请求。在 Linux 系统中,socket 是一种特殊的文件描述符,用于在网络中的不同主机间或者同一台主机中的不同进程间进行双向通信。函数时,如果存在待处理的连接请求,它会创建一个新的已连接套接字,并从队列中移除该请求。
网络编程Socket之TCP之close/shutdown详解
小T是我
07-20 9497
close: 当套接字的引用计数为0的时候才会引发TCP的四分组连接终止序列;   shutdown: 不用管套接字的引用计数就激发TCP的正常连接终止序列; 这里由一个SO_LINGER套接字选项 struct linger {      int l_onoff; /* 0 = off, nozero = on */      int l_linger;
closeshutdown
扎实基础方能走远
01-17 1075
closeshutdown都是关闭套接字的系统调用函数 区别如下:   先说包交互流程: close会直接发送FIN包,并且(一般情况)不再接收对方发送的任何报文,如果有收到报文会回复RST。 shutdown有三类情况: 1,在参数是SHUT_RD,也就是只关闭了读的时候,是不会发送任何表明关闭了读的协议报文的。同时对端还可以发送报文,本端也会回复ack,但是本端在用系统调用rec...
关于closeshutdown区别
狂客队长
03-16 4957
终止网络连接的通常方法是调用close函数。不过close有两个限制,却可以使用shutdown来避免。 1  close把描述字的引用计数减1,仅在该计数变为0的时候才关闭套接口。而使用shutdown可以不管引用计数的值是多少就激发TCP的正常连接终止序列,也即是发送FIN节。 2  close终止数据传送的两个方向:读和写。而有的时候只是想关闭读或写,那么此时就使用shutdown函数进
网络closeshutdown
bandaoyu的note
07-29 1103
目录 区别 详细 问题和陷阱 示例代码 区别 shutdown() 用来关闭连接,而不是套接字,不管调用多少次 shutdown(),套接字依然存在,直到调用 close() / closesocket() 将套接字从内存清除。 调用 close()/closesocket() 将丢失输出缓冲区中的数据,而调用 shutdown() 不会。 close终止了数据传送的两个方向,shutdown 可以选择终止哪个方向的数据传送。 首先看一个例子,如下图所示: 客户端发送ABCD...
Socket编程中的强制关闭与优雅关闭及相关socket选项
01-21 1万+
<br /><br />以下描述主要是针对windows平台下的TCP socket而言。<br />首先需要区分一下关闭socket和关闭TCP连接的区别,关闭TCP连接是指TCP协议层的东西,就是两个TCP端之间交换了一些协议包(FIN,RST等),具体的交换过程可以看TCP协议,这里不详细描述了。而关闭socket是指关闭用户应用程序中的socket句柄,释放相关资源。但是当用户关闭socket句柄时会隐含的触发TCP连接的关闭过程。<br />TCP连接的关闭过程有两种,一种是优雅关闭(gracef
socket关闭closeshutdown
mayue_web的博客
02-22 5545
转载:http://blog.sina.com.cn/s/blog_693de6100101eusw.html 概述 socket关闭有2个方法closeshutdown ,2个方法的用法需要注意 ,他们之间的区别: close-----关闭本进程的socket id,但链接还是开着的,用这个socket id的其它进程还能用这个链接,能读或写这个socket id shutdown–则破坏了s...
shutdownclose区别
Phoenix_FuliMa
05-07 1万+
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作: close(sockfd);    你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输继续进行。如你可以关 闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。
socket中的closeshutdown区别
认真就赢了
04-05 3944
很明显这个两个函数是有差别的。close关闭本进程的socket id,但链接还是开着的。怎么理解?我们知道socket描述符是对内核中socket对象的引用。而close操作的正式socket描述符,可以理解为断开了当前进程和内核中socket对象的关系。但是其他进程同样可以和这个socket对象建立关系。当然也就是说连接是开着的(因为其他进程可以通过socket读写数据)shutdown破坏了s
驱动 shutdown函数
07-27
shutdown函数是一个用于关闭计算机或终止程序的函数。在C语言中,可以使用以下代码调用shutdown函数: ```c #include <stdlib.h> #include <unistd.h> int main() { // ... shutdown(0); // 调用shutdown函数 return 0; } ``` 在上面的示例中,shutdown函数被调用并传递了一个参数0。这个参数指示关闭计算机或终止程序的方式。具体的行为取决于操作系统和权限设置。请注意,调用shutdown函数通常需要具有适当的权限。
写文章

热门文章

  • 死区时间的分析与设置 23193
  • C++总结(7):STL无序容器之unordered_set、unordered_map、unordered_multiset、unordered_multimap详解 21814
  • LVGL学习(3):页面切换原理和页面管理实现 19592
  • Git合并操作之merge、rebase、squash详解 19143
  • CRC校验(2):CRC32查表法详解、代码实现和CRC反转 15337

分类专栏

  • Peripheral 6篇
  • 嵌入式 23篇
  • algorithm 6篇
  • RT1170 13篇
  • 应用 5篇
  • 嵌入式Linux 14篇
  • ARM 20篇
  • 嵌入式硬件 1篇
  • LVGL 6篇
  • Linux 6篇
  • RTOS 4篇
  • 网络编程 13篇
  • git 3篇
  • C++ 10篇
  • BLE 6篇
  • FOC 7篇
  • LwIP 4篇
  • 模拟电路 4篇

最新评论

  • LVGL学习(5):物理按键切换焦点之焦点保存和恢复

    WolverineKT: 你最后总结的那个方法,不是很理解,有代码参考吗

  • 单片机(STM32,GD32,NXP等)中BootLoader的严谨实现详解

    ABC_12347567245: bootloader的代码和APP代码是分开的吗?

  • LVGL学习(3):页面切换原理和页面管理实现

    RRainbowW: 佬,您好,可以和您讨要一份源码么,供学习LVGL页面管理使用,合适的话,您发我邮箱可以么,2428853644@qq.com谢谢您!

  • CORDIC算法 arctan反正切计算原理及C语言定点实现

    亦久亦旧a: 求acrtan(1),第一次旋转就是45°,但是y2 不等于0啊表情包

  • USB学习(1):USB基础之接口类型、协议标准、引脚分布、架构、时序和数据格式

    乏力污边: Suffered Bit为Stuffed Bit

最新文章

  • I.MX RT1170之MIPI CSI摄像头初始化和显示流程详解
  • I.MX RT1170之MIPI DSI初始化和显示流程详解
  • C语言实现Hash Map(3):Map代码优化
2024年19篇
2023年75篇
2022年43篇
2021年19篇
2020年4篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tilblackout

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家淮北玻璃钢雕塑工厂南京玻璃钢雕塑制作工厂新郑抽象玻璃钢卡通雕塑公司宿州卡通玻璃钢雕塑安装上海中庭商场美陈价格清远古代玻璃钢卡通雕塑楼盘玻璃钢人物雕塑商家合肥端州玻璃钢人物雕塑郑州玻璃钢动物雕塑公司云南仿铜玻璃钢雕塑方法北京常见商场美陈周口玻璃钢花盆生产厂家城市几何玻璃钢雕塑定制深圳透光玻璃钢雕塑厂家湖南景观玻璃钢卡通雕塑公司深圳季节性商场美陈市场霍州玻璃钢园门头雕塑宜春水果玻璃钢雕塑现代风格时尚玻璃钢花盆组合安顺玻璃钢雕塑设计银川玻璃钢雕塑厂家云浮玻璃钢动物雕塑销售厂质量好的玻璃钢花盆西藏玻璃钢桃子雕塑临澧玻璃钢造型雕塑电镀玻璃钢雕塑定制厂家玻璃钢动物雕塑 临朐泰州玻璃钢仿铜雕塑厂家供应宁波玻璃钢仿铜雕塑济南定制玻璃钢雕塑批发香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化