热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

为什么即使Linux服务器的socket关闭,客户端仍能调用一次send函数?

要弄清这个问题,首先需要知道调用send()发送数据时,发生了什么。当调用send()发送数据时,并不是直接将数据发送到网络中,而是先将待发送的数据放到socket发送缓冲区中,然

要弄清这个问题,首先需要知道调用send()发送数据时,发生了什么。

当调用send()发送数据时,并不是直接将数据发送到网络中,而是先将待发送的数据放到socket发送缓冲区中,然后由TCP协议执行数据的网络发送。send()函数不保证数据能够通过网络成功发送出去,只要能够将数据写入到socket发送缓冲区,send()就可以成功返回。

 当服务器socket突然关闭时,客户端并不知情,此时客户端调用send()依然可以将数据放置到socket发送缓冲区中,所以send()成功返回。直到TCP协议执行发送动作的时候才发现不对劲~~~~这时客户端才拿到服务器socket已关闭的信息,由于TCP协议无法继续网络数据的传输,所以系统自动关闭客户端socket发送缓冲区的读端。这时,再次调动send()函数,就会导致程序终止。原因是收到了SIGPIPE信号,这说明socket发送缓冲区应该是一个特殊的管道。

以下程序模拟了这个过程,

/* server.c */
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVERIP "192.168.2.134"
int main()
{
int ret;
//创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd == -1)
{
perror("socket");
return -1;
}
//设置地址复用
int opt = 1;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
//填充服务器地址信息
struct sockaddr_in seraddr;
memset(&seraddr, 0, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(8999);
seraddr.sin_addr.s_addr = inet_addr(SERVERIP);
//绑定
ret = bind(sfd, (struct sockaddr*)&seraddr, sizeof(seraddr));
if (ret == -1)
{
perror("bind");
return -1;
}
//监听
listen(sfd, 5);
//等待连接
struct sockaddr_in cliaddr;
memset(&cliaddr, 0, sizeof(cliaddr));
socklen_t len = sizeof(cliaddr);
int cfd = accept(sfd, (struct sockaddr*)&cliaddr, &len);
//处理连接事务
printf("欢迎%s:%d访问!\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
char buffer[64] = {0};
while (1)
{
recv(cfd, buffer, sizeof(buffer), 0);
fputs(buffer, stdout);
}
return 0;
}

/* client.c */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVERIP "192.168.2.134"
#define SERVERPORT 8999
typedef void (*sighandler_t)(int);
void sig_handler(int signum)
{
printf("果然裂开了!!!!\n");
exit(0);
}
int main()
{
int ret;
char buffer[64];
//捕获信号
signal(SIGPIPE, sig_handler);
//创建套接字
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if (cfd == -1)
{
perror("socket");
return -1;
}
//填充目标服务器地址信息
struct sockaddr_in cliaddr;
memset(&cliaddr, 0, sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(SERVERPORT);
cliaddr.sin_addr.s_addr = inet_addr(SERVERIP);
//请求连接
ret = connect(cfd, (struct sockaddr*)&cliaddr, sizeof(cliaddr));
if (ret == -1)
{
perror("connect");
return -1;
}
//处理与服务器的交互事务
while (1)
{
fgets(buffer, sizeof(buffer), stdin);
send(cfd, buffer, strlen(buffer)+1, 0);
}
return 0;
}

 如上,成功发送了"hello"、"dont leave"后,强制停止服务器进程,这时客户端继续发送"are you here?",send()成功返回,"are you here?"被成功写到发送缓冲区,但是无法通过TCP协议发送到网络中,当下一次发送"????"时,就收到了SIGPIPE信号,被自定义的信号处理函数捕获到。


推荐阅读
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 通过Web界面管理Linux日志的解决方案
    本指南介绍了一种利用rsyslog、MariaDB和LogAnalyzer搭建集中式日志管理平台的方法,使用户可以通过Web界面查看和分析Linux系统的日志记录。此方案不仅适用于服务器环境,还提供了详细的步骤来确保系统的稳定性和安全性。 ... [详细]
  • 本文详细解释了华为ENSP模拟器中常用的命令,涵盖用户模式、系统模式、接口模式和地址池视图模式下的操作。这些命令对于进行计算机网络实验至关重要,帮助用户更好地理解和配置路由器及PC机的通信。 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • 华为USG基于源地址的多出口策略路由配置
    网络拓扑如下:组网情况:企业用户主要有技术部(VLAN10)和行政部(VLAN20),通过汇聚交换机连接到USG。企业分别通过两个不同运营商(ISP1和ISP2)连接到 ... [详细]
  • FinOps 与 Serverless 的结合:破解云成本难题
    本文探讨了如何通过 FinOps 实践优化 Serverless 应用的成本管理,提出了首个 Serverless 函数总成本估计模型,并分享了多种有效的成本优化策略。 ... [详细]
  • Java 数组及其常用操作
    本文详细介绍了 Java 中的数组类型、定义方法以及常见操作,帮助开发者更好地理解和使用 Java 数组。 ... [详细]
  • 探讨如何从数据库中按分组获取最大N条记录的方法,并分享新年祝福。本文提供多种解决方案,适用于不同数据库系统,如MySQL、Oracle等。 ... [详细]
  • 本文详细介绍了网络存储技术的基本概念、分类及应用场景。通过分析直连式存储(DAS)、网络附加存储(NAS)和存储区域网络(SAN)的特点,帮助读者理解不同存储方式的优势与局限性。 ... [详细]
  • 本文介绍了Linux系统中的文件IO操作,包括文件描述符、基本文件操作函数以及目录操作。详细解释了各个函数的参数和返回值,并提供了代码示例。 ... [详细]
  • 本文详细介绍了Wi-Fi Portal认证协议的原理、流程和相关技术细节,涵盖用户上线认证、下线流程以及数据报文格式等内容。 ... [详细]
  • C# LiNQ 查询 join连接
    C# LiNQ 查询 join连接 ... [详细]
  • 不确定性|放入_华为机试题 HJ9提取不重复的整数
    不确定性|放入_华为机试题 HJ9提取不重复的整数 ... [详细]
  • 本文详细介绍如何利用已搭建的LAMP(Linux、Apache、MySQL、PHP)环境,快速创建一个基于WordPress的内容管理系统(CMS)。WordPress是一款流行的开源博客平台,适用于个人或小型团队使用。 ... [详细]
  • 本主题面向IT专业人士,介绍了Windows Server 2012 R2和Windows Server 2012中的组托管服务账户(gMSA),涵盖了其应用场景、功能改进、硬件和软件要求以及相关资源。 ... [详细]
author-avatar
Perz
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有