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

news2024/11/18 19:26:48

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

文章目录

  • 1 close
  • 2 shutdown
  • 3 实例:shutdown的使用
    • 3.1 代码修改
    • 3.2 实验结果
    • 3.3 完整代码

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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1270107.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ESP32-Web-Server编程- WebSocket 编程

ESP32-Web-Server编程- WebSocket 编程 概述 在前述 ESP32-Web-Server 实战编程-通过网页控制设备的 GPIO 中&#xff0c;我们创建了一个基于 HTTP 协议的 ESP32 Web 服务器&#xff0c;每当浏览器向 Web 服务器发送请求&#xff0c;我们将 HTML/CSS 文件提供给浏览器。 使用…

Linux相关--笔试和面试高频

Linux RedHat公司已经宣布停止维护CentOS服务器操作系统&#xff0c;可以选择华为开源的欧拉系统、阿里开源的龙蜥系统和腾讯开源的TencentOS系统 面试 几个基本的Linux命令 pwd #查看当前绝对路径 结果/home/stu touch / vi编辑器 #创建文件 mkdir -p /home/stu/test #当…

智能工厂是什么?

今天就聊聊企业智能工厂的打造&#xff0c;企业想实现数字化转型建立智能工厂&#xff0c;就需要先建设数字化车间&#xff0c;可以说数字化车间是建设智能工厂的重要一环&#xff0c;智能工厂的基础是数字化车间。数字化车间可以实现企业生产过程中车间计划调度、工艺执行管理…

高项备考葵花宝典-项目范围管理输入、输出、工具和技术

项目范围管理包括确保项目“做”且“只做”所需的全部工作&#xff08;即不能少做&#xff0c;也不能多做&#xff0c;如果多做&#xff0c;就要消耗团队额外的时间和资源&#xff0c;并且无法被认可&#xff09;&#xff0c;以成功完成项目。项目范围管理主要在于定义和控制哪…

【MySQL数据库】SQL查询语句总结

目录 一、查询数据 1.1 基本查询语句 1.2 表单查询 1.3 WHERE子句 1.3.1 IN关键字查询 1.3.2 Between查询范围 1.3.3 Like匹配查询 1.3.4 AND多条件查询&#xff08;等同于&&&#xff09; 1.3.5 OR多条件查询&#xff08;等同于||&#xff09; 1.3.6 LIMIT子句 1.3.7 对…

聚观早报 |亚马逊AWS发布新AI芯片;拼多多Q3营收增长94%

【聚观365】11月30日消息 亚马逊AWS发布新AI芯片 拼多多Q3营收增长94% Redmi K70全新国风配色揭晓 英伟达扩大自动驾驶中国团队 华为nova 12参数细节曝光 亚马逊AWS发布新AI芯片 在美国时间周二举办的Reinvent大会上&#xff0c;亚马逊旗下的云计算部门AWS发布了新的人工…

【开源视频联动物联网平台】为什么需要物联网网关?

在一些物联网项目中&#xff0c;物联网网关这一产品经常被涉及。那么&#xff0c;物联网网关究竟有何作用&#xff1f;具备哪些功能&#xff1f;同时&#xff0c;我们也发现有些物联网设备并不需要网关。那么&#xff0c;究竟在何时需要物联网网关呢&#xff1f; 物联网的架构…

linux安装minIo(亲测可用)

一、创建文件夹 进入opt文件夹 cd /opt/创建minio文件夹&#xff1b; mkdir minio赋予权限 chmod 777 minio/执行完后查看目录 进到minio文件夹 创建bin目录 mkdir bin创建data目录 mkdir data创建log touch minio.log创建start.sh文件&#xff0c;并写入数据(不会vi或…

Stream API练习题

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 考虑到Stream API在实际…

abapgit 安装及使用

abapgit 需求 SA[ BASIS 版本 702 及以上 版本查看路径如下&#xff1a; 安装步骤如下&#xff1a; 1. 下载abapgit 独立版本 程序 链接如下&#xff1a;raw.githubusercontent.com/abapGit/build/main/zabapgit_standalone.prog.abap 2.安装开发版本 2.1 在线安装 前置条…

智慧公厕为城市智慧管理提供强力有的数据支持

在当今科技飞速发展的时代&#xff0c;城市管理正面临着前所未有的挑战与机遇。而在这个城市发展的脚步日新月异的同时&#xff0c;一项看似不起眼的技术却正在默默地为城市的智慧管理提供着强有力的支持——那就是智慧公厕。这些不起眼的公共设施不仅仅是人们日常生活的一部分…

Linux系统平均负载

我们经常会使用 top 命令来查看系统的性能情况&#xff0c;在 top 命令的第一行可以看到 load average 这个数据&#xff0c;如下图所示&#xff1a; load average 包含 3 列&#xff0c;分别表示 1 分钟、5 分钟和 15 分钟的 系统平均负载 系统平均负载&#xff1a; 如果将 …

多媒体信号处理复习笔记 --脑图版本

多媒体信号处理复习笔记 --脑图版本 依据 [2020多媒体信号处理复习笔记] 考前复习时使用Xmind制作 例图: PDF下载 BaiduYunPan 提取码&#xff1a;jbyw CSDN 下载

LeetCode2514.统计同位异构字符串数目

题目简单&#xff0c;关键是灵茶山艾府的代码写起来太优美&#xff0c;不得不记录一下 const int Mod 1e97; using ll long long; ll qmi(ll a,ll b,ll mod){ll res 1;while(b){if(b&1)res res*a%mod;aa*a%mod;b>>1;}return res; }class Solution { public:int c…

[黑皮系列] 计算机网络:自顶向下方法(第8版)

文章目录 《计算机网络&#xff1a;自顶向下方法&#xff08;第8版&#xff09;》简介作者目录前言配套公开课 《计算机网络&#xff1a;自顶向下方法&#xff08;第8版&#xff09;》 出版信息&#xff1a; 原作名: Computer Networking: A Top-Down Approach 作者: [美] Jame…

LangChain 15根据问题自动路由Router Chain确定用户的意图

LangChain系列文章 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数据库Faiss存储&#xff0c;读取YouTube的视频文本搜索I…

ApiSix的docker 容器化部署及使用

⼀&#xff0e;etcd安装 Docekr安装Etcd 环境准备 此处安装&#xff0c;是利⽤下载的 etcd 源⽂件&#xff0c;利⽤ docker build 构建完整镜像&#xff0c;具体操作如下&#xff1a; 1.环境准备 1.1. 新建⽂件夹 在磁盘某个路径下新建⼀个⽂件夹&#xff0c;⽤处操作 Dockerfi…

13:kotlin类和对象 -- 属性(Properties)

定义属性 类属性可使用var和val定义 class Address {var name: String "Holmes, Sherlock"var street: String "Baker"var city: String "London"var state: String? nullvar zip: String "123456" }属性使用 fun copyAddres…

00Hadoop数据仓库平台

在这里是学习大数据的第一站 什么是数据仓库常见大数据平台组件及介绍 什么是数据仓库 在计算领域&#xff0c;数据仓库&#xff08;DW 或 DWH&#xff09;也称为企业数据仓库&#xff08;EDW&#xff09;&#xff0c;是一种用于报告和数据分析的系统&#xff0c;被认为是商业智…

深度学习实现语义分割算法系统 - 机器视觉 计算机竞赛

文章目录 1 前言2 概念介绍2.1 什么是图像语义分割 3 条件随机场的深度学习模型3\. 1 多尺度特征融合 4 语义分割开发过程4.1 建立4.2 下载CamVid数据集4.3 加载CamVid图像4.4 加载CamVid像素标签图像 5 PyTorch 实现语义分割5.1 数据集准备5.2 训练基准模型5.3 损失函数5.4 归…