服务器后台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,然后向服务器 ...
随机推荐
- android图片的异步加载和双缓存学习笔记——DisplayImageOptions (转)
转的地址:http://hunankeda110.iteye.com/blog/1897961 1 //设置图片在下载期间显示的图片 2 showStubImage(R.drawable.ic_lau ...
- Activity has leaked window that was originally added -界面退出时未关闭对话框异常 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? -
退出Activity时弹出登录框,点击确定finish当前Activity,结果报了这个错,随后查找资料知道 原因: 是因为退出Activity时没有关闭弹出框,出现了这个错误 解决方法: 只需要在a ...
- 网页提示[Not allowed to load local resource: file://XXXX]错误
网页通过http 访问时, 点击打开文件的link.在Chrome 中会报 Not allowed to load local resource: file// XXXX 的错误 <!--Add ...
- vim选中字符复制/剪切/粘贴
转载自:http://www.cnblogs.com/luosongchao/p/3193153.html 问题描述: vim 中选中指定字符,进行复制/剪切/粘贴 选择:1.普通模式下--v+hjk ...
- SPAN的高度问题
FIRST OF ALL,最容易令人忽略而导致头疼的因素.web页面文档类型: 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Trans ...
- 【Codeforces 707B】Bakery 水题
对每个storages找一下最短的相邻边 #include <cstdio> #define N 100005 #define inf 0x3f3f3f3f using namespace ...
- 【LintCode】删除链表中的元素
问题分析: 声明当前指针和上一个指针即可. 问题求解: public class Solution { public ListNode removeElements(ListNode head, in ...
- Leetcode #2 Add two number
Q: You are given two linked lists representing two non-negative numbers. The digits are stored in re ...
- Lamp源码搭建
Lamp Centos6.5 + Apache/2.2.29 + PHP 5.3.29 + Mysql5.6.20 Apache(/usr/local/apache) PHP(/usr/local/b ...
- 根据html容器大小和显示文字多少调节字体大小
在做html相关的东西的时候经常会遇到这样的问题,容器大小(长x宽)固定,容器包含内容(特指文字)多少不固定,这个时候就让人很苦恼了,将字体大小设置成多少才合适呢?下面看看我的解决思路: 首先要知道网 ...