当前位置: 首页 > news >正文

网络编程close学习

1、概述

下面问题你会怎么回答?

希望发完一个数据后关闭连接,且希望对端的应用层尽量收到?代码可以这么写么?

send(fd, buf, .....);

close(fd);

2、分析

上述代码是不行的,send返回成功仅表示数据拷贝到内核tcp发送缓冲区,不代表数据发送到对端;直接调用close会导致内核缓冲区未发送的数据被丢弃,无法保证对端完整接收。

2.1、解决办法

2.1.1、Linger选项

Linger选项是控制socket关闭时的行为,当设置Linger选项后,调用close函数时若内核缓冲区还有数据,会等待指定时间,如果等待时间内数据未能成功发送,这些缓冲区数据会被丢弃。
Linger选项结构体,调用setsockopt设置,如下:

typedef struct linger {u_short l_onoff; //0关闭,1打开,默认是关闭的u_short l_linger;
} LINGER, *PLINGER, *LPLINGER;
struct linger ling;
ling.l_onoff = 1;    // 0关闭,1打开
ling.l_linger = 30;  // 等待 30 秒,超时强制关闭setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));// 阻塞直到 30 秒,或数据发完
int ret = close(sockfd);

这里会有俩种情况,

等待时间足够长,数据可以成功发送。(服务端一般不允许设置长时间等待,可能会耗尽资源)

等待时间短,可能出现数据部分发送成功或全部被丢弃的情况。

所以Linger选项可以是我们的备选方案。

2.1.2、shutdown(SH_WR)

socket工作是全双工的,读和写是分别独立的。

shutdown函数可以单独关闭读或写方向,close是关闭整个连接。

// how是SHUT_RD,本端读通道关闭,对端不能再写数据
// how是SHUT_WD,本端写通道关闭,对端不能再读数据
int shutdown(int sockfd, int how);

调用完send发送数据,可以调用shutdown(fd, SHUT_WD)告诉对端数据发送完毕,但接收通道仍开放。对端应用层收完数据后会回复ack,并调用close函数,此时可以安全调用close函数关闭连接。这是tcp半关闭问题!!!,感兴趣读者可再深入学习。

示例代码如下:

【服务端】

// 1. 发送数据
if (send(sockfd, data, len, 0) < 0) {perror("send failed");close(sockfd);return;
}// 2. 【关键】关闭写方向,通知对端“我发完了”
if (shutdown(sockfd, SHUT_WR) < 0) {perror("shutdown failed");close(sockfd);return;
}
// 此时本端不能 send() 了,但还能 recv()// 3. 等待对端的应用层确认(ACK)
char ack[4];
ssize_t n = recv(sockfd, ack, sizeof(ack), 0);
if (n > 0 && memcmp(ack, "ACK", 3) == 0) {printf("Received ACK from client, data processed.\n");
} else {printf("No ACK received.\n");
}// 4. 安全关闭
close(sockfd);

【客户端】

// 客户端 recv 到所有数据后
char buf[1];
while (recv(sockfd, buf, 1, 0) > 0) {// 处理数据
}// recv 返回 0,表示对端 shutdown(SHUT_WR),数据发送完毕
printf("Server finished sending data.\n");// 发送 ACK 确认
send(sockfd, "ACK", 3, 0);// 可以 close
close(sockfd);

学习链接:https://github.com/0voice

http://www.dtcms.com/a/352293.html

相关文章:

  • Java大厂面试实录:从Spring Boot到Kubernetes的全链路技术突围
  • python命名规则(PEP 8 速查表),以及自定义属性
  • 深度感知卷积和深度感知平均池化
  • python自动测试 crictl 可以从哪些国内镜像源成功拉取镜像
  • pulsar、rocketmq常用命令
  • C#由Dictionary不正确释放造成的内存泄漏问题与GC代系
  • Text to Speech技术详解与实战:GPT-4o Mini TTS API应用指南
  • 从“脚本语言”到“企业级引擎”——PHP 在 2025 年技术栈中的再定位
  • Linux服务器安全配置与NTP时间同步
  • 记录一下,qt问题:qt ui文件的改动无法更新到cpp
  • 疯狂星期四文案网第51天运营日记
  • Typescript入门-interface讲解
  • 类型签名,位置参数,关键字参数
  • open webui源码分析8—管道
  • 域名常见问题集(十一)——为什么要进行域名管理?
  • 【实时Linux实战系列】基于实时Linux的音频实时监控系统
  • 从16个粉丝到680万年收入:AI创业的117天奇迹
  • 声明式微服务通信新范式:OpenFeign如何简化RestTemplate调用
  • Windows下实现类似`watch nvidia-smi`的实时监控效果
  • 进入docker中mysql容器的方法
  • Java:TreeSet的使用
  • (Arxiv-2024)VideoMaker:零样本定制化视频生成,依托于视频扩散模型的内在力量
  • QT qml(quick3D)模型的移动
  • 专业解读《Light》封面:可调谐混合超表面(THCMs)如何革新下一代LiDAR系统
  • 3D游戏角色建模资源搜索指南(资料来源于网络)
  • 湖仓一体:小米集团基于 Apache Doris + Apache Paimon 实现 6 倍性能飞跃
  • JavaWeb之分布式事务规范
  • LInux(二十一)——Linux SSH 基于密钥交换的自动登录原理简介及配置说明
  • jenkins2025配置邮箱发送
  • 基于Android的车位预售预租APP/基于Android的车位租赁系统APP/基于Android的车位管理系统APP