热门标签 | 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信号,被自定义的信号处理函数捕获到。


推荐阅读
  • 本文探讨了一种常见的C++面试题目——实现自己的String类。通过此过程,不仅能够检验开发者对C++基础知识的掌握程度,还能加深对其高级特性的理解。文章详细介绍了如何实现基本的功能,如构造函数、析构函数、拷贝构造函数及赋值运算符重载等。 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 想把一组chara[4096]的数组拷贝到shortb[6][256]中,尝试过用循环移位的方式,还用中间变量shortc[2048]的方式。得出的结论:1.移位方式效率最低2. ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ... [详细]
  • C/C++中一级指针的内存模型与示例代码
    本文通过一个具体的C/C++代码示例,详细解析了一级指针在内存中的布局和工作原理。包括了对不同类型的指针变量如何在内存中分配空间的讨论。 ... [详细]
  • C/C++ 应用程序的安装与卸载解决方案
    本文介绍了如何使用Inno Setup来创建C/C++应用程序的安装程序,包括自动检测并安装所需的运行库,确保应用能够顺利安装和卸载。 ... [详细]
  • 本文提供了一个关于AC自动机(Aho-Corasick Algorithm)的详细解析与实现方法,特别针对P3796题目进行了深入探讨。文章不仅涵盖了AC自动机的基本概念,还重点讲解了如何通过构建失败指针(fail pointer)来提高字符串匹配效率。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • 【MySQL】frm文件解析
    官网说明:http:dev.mysql.comdocinternalsenfrm-file-format.htmlfrm是MySQL表结构定义文件,通常frm文件是不会损坏的,但是如果 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 本文详细介绍了如何在 Ubuntu 14.04 系统上搭建仅使用 CPU 的 Caffe 深度学习框架,包括环境准备、依赖安装及编译过程。 ... [详细]
  • Hanks博士是一位著名的生物技术专家,他的儿子Hankson对数学有着浓厚的兴趣。最近,Hankson遇到了一个有趣的数学问题,涉及求解特定条件下的正整数x,而不使用传统的辗转相除法。 ... [详细]
  • MITM(中间人攻击)原理及防范初探(二)
    上一篇文章MITM(中间人攻击)原理及防范初探(一)给大家介绍了利用ettercap进行arp欺骗及劫持明文口令,后来我发现好友rootoorotor的文章介绍比我写的更透彻,所以基础利用大家可以参看 ... [详细]
  • 本文详细介绍了Linux系统中信号量的相关函数,包括sem_init、sem_wait、sem_post和sem_destroy,解释了它们的功能和使用方法,并提供了示例代码。 ... [详细]
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社区 版权所有