服务器后台TCP连接存活问题
0. 背景
公司的服务器后台部署在某一个地方,接入的是用户的APP,而该地方的网络信号较差,导致了服务器后台在运行一段时间后用户无法接入,那边的同事反馈使用netstat查看系统,存在较多的TCP连接。
1. 问题分析
首先在公司内部测试服务器上部署,使用LoadRunner做压力测试,能正常运行,然后那边的同事反馈该地方信号较差。考虑到接入的问题,有可能接入进程的FD资源耗尽,导致accept失败。推论的依据是对于TCP连接来说,如果客户端那边由于一些异常情况导致断网而未能向服务器发起FIN关闭消息,服务端这边若没有设置存活检测的话,该连接会存在(存活时间暂未测)。
2. 实验测试
这里简单地写了一个服务端的程序,主要功能是回应,即接受一个报文(格式:2Byte报文长度+报文内容),然后原封不动将报文内容发回客户端。
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h> int g_epfd; int InitServer( unsigned short port )
{
int nServerFd = socket( AF_INET, SOCK_STREAM, ); struct sockaddr_in addr;
memset( &addr, , sizeof(addr) ); addr.sin_family = AF_INET;
addr.sin_port = htons( port );
addr.sin_addr.s_addr = ; if ( bind( nServerFd, (struct sockaddr *)&addr, sizeof(addr) ) < )
{
printf("bind error\n");
exit(-);
} if ( listen( nServerFd, ) < )
{
printf("listen error\n");
exit(-);
} return nServerFd;
} int AddFd( int epfd, int nFd , int nOneShot)
{
struct epoll_event event;
memset( &event, , sizeof( event) ); event.data.fd = nFd;
event.events |= EPOLLIN | EPOLLRDHUP | EPOLLET; if ( nOneShot ) event.events |= EPOLLONESHOT; return epoll_ctl( epfd, EPOLL_CTL_ADD, nFd, &event );
} int ResetOneShot( int epfd, int nFd )
{
struct epoll_event event;
memset( &event, , sizeof(event) ); event.data.fd = nFd;
event.events |= EPOLLIN | EPOLLRDHUP | EPOLLONESHOT; return epoll_ctl( epfd, EPOLL_CTL_MOD, nFd, &event);
} void * ReadFromClient( void * arg )
{
int nClientFd = (int)arg;
unsigned char buf[];
const int nBufSize = sizeof( buf );
int nRead;
int nTotal;
int nDataLen; printf("ReadFromClient Enter\n"); if ( (nRead = read( nClientFd, buf, )) != )
{
printf("Read Data Len error\n");
pthread_exit(NULL);
} nDataLen = *(unsigned short *)buf;
printf("nDataLen [%d]\n", nDataLen);
nDataLen = buf[]* + buf[];
printf("nDataLen [%d]\n", nDataLen); nRead = ;
nTotal = ;
while( )
{
nRead = read( nClientFd, buf + nRead, nBufSize );
if ( nRead < )
{
printf("Read Data error\n");
pthread_exit( NULL );
}
nTotal += nRead;
if ( nTotal >= nDataLen )
{
break;
}
}
printf("nTotal [%d]\n", nTotal); sleep(); int nWrite = write( nClientFd, buf, nTotal );
printf("nWrite[%d]\n", nWrite); printf("Not Write ResetOneShot [%d]\n", ResetOneShot(g_epfd, nClientFd)); return NULL;
} int main(int argc, char const *argv[])
{
int i;
int nClientFd;
pthread_t tid;
struct epoll_event events[]; int nServerFd = InitServer( );
if ( nServerFd < )
{
perror( "nServerFd" );
exit(-);
} int epfd = epoll_create( ); g_epfd = epfd; int nReadyNums; if ( AddFd( epfd, nServerFd, ) < )
{
printf("AddFd error\n");
exit(-);
} while( )
{
nReadyNums = epoll_wait( epfd, events, , -1 ); if ( nReadyNums < )
{
printf("epoll_wait error\n");
exit(-);
} for ( i = ; i < nReadyNums; ++i)
{
if ( events[i].data.fd == nServerFd )
{
nClientFd = accept( nServerFd, NULL, NULL ); AddFd( epfd, nClientFd, ); }else if ( events[i].events & EPOLLIN )
{
// Can be implemented by threadpool
//Read data from client
pthread_create( &tid, NULL, ReadFromClient, (void *)(events[i].data.fd) ); }else if ( events[i].events & EPOLLRDHUP )
{
//Close By Peer
printf("Close By Peer\n");
close( events[i].data.fd );
}else
{
printf("Some thing happened\n");
} }
} return ;
}
测试内容:
注:客户端IP: 192.168.10.108 服务器IP&Port: 192.168.10.110:7777
a. 客户端发送一个报文至服务端,然后断网。(这里对程序做了点改动,这次实验注释了write响应,防止write影响测试,后面一个实验会使用write)。
客户端断网后,使用netstat查看网络连接状态发送客户端与服务端还处于established状态,如图所示。
a. 实验结果
服务端没有检测到客户端断网,依然处于连接状态。
b. 客户端发送一个报文至服务端,然后断网,关闭客户端,再重复一次。
这次试验测试重新联网,程序再次建立Socket连接是否会导致之前的连接被检测到。
b. 实验结论:
重新联网,程序再次建立Socket连接之前的连接不会被检测到。
c. 客户端发送一个报文至服务端,然后断网。(这次实验使用了write响应,查看write后的结果)。
这里查看到Write居然成功了,成功了....。
c. 实验结论:
这次使用write不会检测对端是否已经断了。
3. 解决方案
临时:使用TCP的选项SO_KEEPALIVE检测客户端是否已异常掉了(setsockopt)。
后续改进:使用心跳包来检测长连接存活问题。
注:SO_KEEPALIVE明天再补充,回家了,只有一台笔记本直接装了Ubuntu,没装虚拟机,伤不起。
4. 补充
如果什么不对的或者建议直接说,多讨论讨论比较好。
服务器后台TCP连接存活问题的更多相关文章
- server后台TCP连接存活问题
公司的server后台部署在某一个地方,接入的是用户的APP,而该地方的网络信号较差,导致了server后台在执行一段时间后用户无法接入,那边的同事反馈使用netstat查看系统.存在较多的TCP连接 ...
- 单台服务器最大tcp连接
如果对服务器进行压力测试,常常出现这种情况 tcp连接数过多 netstat -an windows查看tcp连接数 那么怎么增加单台服务器的最大连接数呢? 最简单的办法,增加内 ...
- 【故障公告】推荐系统中转站撑爆服务器 TCP 连接引发的故障
上周五下午,我们在博客中部署了推荐系统,在博文下方显示“最新IT新闻”的地方显示自动推荐的关联博文.我们用的推荐系统是第四范式的推荐服务,我们自己只是搭建了一个推荐系统中转站(基于 ASP.NET C ...
- TCP 连接
面试题传送 TCP 报文格式 此处介绍建立或者断开TCP连接时,需要了解的TCP报文段首部字段含义: 序列号 seq:占4个字节(32位),用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上 ...
- 简述TCP连接的建立与释放(三次握手、四次挥手)
在介绍TCP连接的建立与释放之前,先回顾一下相关知识. TCP是面向连接的运输层协议,它提供可靠交付的.全双工的.面向字节流的点对点服务.HTTP协议便是基于TCP协议实现的.(虽然作为应用层协议,H ...
- TCP连接中time_wait在开发中的影响-搜人以鱼不如授之以渔
根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),T ...
- TCP连接的建立与释放(三次握手与四次挥手)
TCP连接的建立与释放(三次握手与四次挥手) TCP是面向连接的运输层协议,它提供可靠交付的.全双工的.面向字节流的点对点服务.HTTP协议便是基于TCP协议实现的.(虽然作为应用层协议,HTTP协议 ...
- 网络学习笔记(一):TCP连接的建立与关闭
五层网络模型分为:物理层.数据链路层.网络层.传输层.应用层.其中,传输层有两种主要协议:面向连接的TCP(Transmission Control Protocol 传输控制协议).无连接的UD ...
- TCP连接与释放
TCP连接的建立 三次握手 TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态. TCP客户进程也是先创建传输控制块TCB,然后向服务器 ...
随机推荐
- ScrollView内部元素如何做到fill_parent 或者 match_parent?
转 : http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0704/1629.html ScrollView滚动视图是指当拥有很多 ...
- springMVC-HelloWorld
1.加入包 2.web.xml 3.利用spring-tool来新建一个springmvc的配置文件 关键步骤,选择创建一个Spring Bean Definition filer 然后next,然后 ...
- Gulp.js----比Grunt更易用的前端构建工具
Gulp.js----比Grunt更易用的前端构建工具 Grunt一直是前端构建工具,然而他也不是毫无缺陷的,gulp的作者 Eric Schoffstall 在他介绍 gulp.js 的 prese ...
- linux内核增加系统调用--Beginner‘s guide
Linux内核中设置了一组用于实现系统功能的子程序,称为系统调用.系统调用和普通库函数调用非常相似明知是系统调用由操作系统核心提供,运行于核心态,而普通的函数调用由函数库或用户自己提供,运行于用户态. ...
- android录音相关
android的麦克风在现在的生活中发挥着很大的作用,打电话,视频聊天,语音识别等等. android sdk的api里提供了很方便的调用方法,下面写一个小的DEMO. 五个按钮:开始录音,停止,播放 ...
- Discuz! X2.5 /source/class/helper/helper_seo.php Remote Code Execution Vul
catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述 SEO模块中的preg_replace+修正符e+双引号引发的远程代码执 ...
- Scala Trait
Scala Trait 大多数的时候,Scala中的trait有点类似于Java中的interface.正如同java中的class可以implement多个interface,scala中的cals ...
- ( 译、持续更新 ) JavaScript 上分小技巧(三)
最近家里杂事较多,自学时间实在少的可怜,所以都在空闲时间看看老外写的内容,学习之外顺便翻译分享~等学习的时间充足些再写写自己的一些学习内容和知识点分析(最近有在接触的:复习(C#,SQL).(学习)T ...
- codevs 1229 数字游戏(可重集的全排列)
传送门 Description Lele 最近上课的时候都很无聊,所以他发明了一个数字游戏来打发时间. 这个游戏是这样的,首先,他拿出几张纸片,分别写上0到9之间的任意数字(可重复写某个数字),然后 ...
- Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
运行环境是win7 x64 sublime text2,百度发现是对齐问题. 具体来说是由于有的地方使用了4个空格,有的地方使用了tab键. 代码区直接全选就会看到有的地方是四个点有个地方是一个横线, ...