手机游戏tcp10 tcp超时时间

  1,TCP连接建立后只要不明确关闭,逻辑上连接一直存在。
  2,TCP是有保活定时器的,可以打开保活定时器来维持长连接,设置SO_KEEPALIVE才会开启,时间间隔默认7200s,也就是2h,这个默认是关闭的。
    注意:HTTP的keepalive和TCP的用处不大一样tcp。
  因为IPv4地址不足, 或者我们想通过无线路由器上网, 我们的设备可能会处在一个NAT设备的后面, 生活中最常见的NAT设备是家用路由器.
  NAT设备会在IP封包通过设备时修改源/目的IP地址. 对于家用路由器来说, 使用的是网络地址端口转换(NAPT), 它不仅改IP, 还修改TCP和UDP协议的端口号, 这样就能让内网中的设备共用同一个外网IP. 举个例子, NAPT维护一个类似下表的NAT表
内网地址外网地址
192.168.0.2:5566
120.132.92.21:9200
192.168.0.3:7788
120.132.92.21:9201
192.168.0.3:8888
120.132.92.21:9202
  NAT设备会根据NAT表对出去和进来的数据做修改, 比如将192.168.0.3:8888发出去的封包改成120.132.92.21:9202, 外部就认为他们是在和120.132.92.21:9202通信. 同时NAT设备会将120.132.92.21:9202收到的封包的IP和端口改成192.168.0.3:8888, 再发给内网的主机, 这样内部和外部就能双向通信了, 但如果其中192.168.0.3:8888 == 120.132.92.21:9202这一映射因为某些原因被NAT设备淘汰了, 那么外部设备就无法直接与192.168.0.3:8888通信了.  国内移动无线网络运营商在链路上一段时间内没有数据通讯后, 会淘汰NAT表中的对应项, 造成链路中断.
  1,心跳的原因:虽然理论tcp连接后一直不断,但实际上会断网。见:比如 NAT超时,更多&
  2,心跳包的主要作用是告知对方连接端,我还活着,心还在跳。
  3,心跳时长多少?
    现实是残酷的, 根据网上的一些说法, 中移动2/3G下, NAT超时时间为5分钟, 中国电信3G则大于28分钟, 理想的情况下, 客户端应当以略小于NAT超时时间的间隔来发送心跳包.
NAT超时时间
中国移动3G和2G
中国联通2G
中国电信3G
大于28分钟
大于28分钟
大于28分钟
    wifi下, NAT超时时间都会比较长, 据说宽带的网关一般没有空闲释放机制, GCM有些时候在wifi下的心跳比在移动网络下的心跳要快, 可能是因为wifi下联网通信耗费的电量比移动网络下小.
心跳包和轮询的区别
心跳包和轮询看起来类似, 都是客户端主动联系服务器, 但是区别很大.
轮询是为了获取数据, 而心跳是为了保活TCP连接.
轮询得越频繁, 获取数据就越及时, 心跳的频繁与否和数据是否及时没有直接关系
轮询比心跳能耗更高, 因为一次轮询需要经过TCP三次握手, 四次挥手, 单次心跳不需要建立和拆除TCP连接.
     
阅读(...) 评论()TCP send频繁调用有多耗?测试过每次花费0.1毫秒?那些号称每秒几十万次的靠谱吗?
TCP send频繁调用有多耗?测试过每次花费0.1毫秒?那些号称每秒几十万次的靠谱吗?
懒得看代码了,试一下TCP_NO_DELAY
--- 共有 26 条评论 ---
: 这么说就释然了, 十分感谢!
: 原来你纠结在这里,人家可能是几台机器一起send,还有一个比较好的服务器都几十个CPU加万兆的局域网
嗯, 之前就怀疑是cpu流水线cache之类的问题,虽然不占CPU,但是别人都号称能够每秒几万次send,那依这个数据来看,因为业务必须要执行其他代码不能一直send,那等业务执行完毕再send就是这么慢,那是怎么做到的?还是他们的结果是建立在连续send上的?
: 如果对延迟有极高的要求,建议去研究实时系统那方面。
: 如果那段for换成sleep,就只有第一个会慢,如果用for就两个都慢,基本可以认为是CPU流水线的问题了。但是差距只在十分之一毫秒之内。
有探索精神,别人测试的可不是普通服务器而是超级计算机。
--- 共有 1 条评论 ---
谢谢,我了解一下
几十万次可不是一台机器啊,是集群。
--- 共有 2 条评论 ---
补充一下,单台硬件并且单线程的能达到几万次吗?
单台几万次呢?
2w次就差不多要花费2秒了, 每秒几万上十万次怎么做到的?
i7, 16G,ubuntu测试
把小包合成打包,减少调用
--- 共有 1 条评论 ---
假设每次已经合并了呢?我只是怀疑那些每秒发送上万次的程序, 如果他们可以做到就是我做错了,因此我需要证明的是每秒几万次cpu还不高是可行的?
高手何在?
send 并不是立马把数据发送出去给对方,而是放入内核对应的缓存区。
setsockopt
getsockopt
--- 共有 1 条评论 ---
这个我知道, 看别人测试libevent说每秒能echo回显8万次, 我测试单次send的消耗是0.1毫秒左右, 8万次是8秒才能做到,我就糊涂了, 是我哪里做错了?
明确告诉你,靠谱。大多数企业能做到1w+的tps(含业务的请求),撇开业务,无复杂业务的IO,10w+很轻松的。
--- 共有 2 条评论 ---
: 测评都是指单服,集群测试比较复杂。单核单线程,只适用无业务的请求,也就是俗话说的玩具。
补充一下,单台硬件并且单线程的能达到几万次吗??
刚测试, java8, i5-4570 8G内存, 本地测试, 30W每秒发送
import java.io.IOE
import java.net.InetSocketA
import java.nio.ByteB
import java.nio.channels.SelectionK
import java.nio.channels.S
import java.nio.channels.ServerSocketC
import java.nio.channels.SocketC
import java.util.I
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
import java.util.concurrent.TimeU
import java.util.concurrent.atomic.AtomicI
* Created by 0x0001 on .
public class NioTest {
private static void server() {
ServerSocketChannel serverSocketC
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 8888), 1024);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
throw new RuntimeException(e);
ByteBuffer buffer = ByteBuffer.allocate(8192);
while(true) {
selector.select();
} catch (IOException e) {
throw new RuntimeException(e);
for (Iterator&SelectionKey& iter = selector.selectedKeys().iterator(); iter.hasNext(); iter.remove()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
SocketChannel client = serverSocketChannel.accept();
if (client.finishConnect()) {
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
int read = client.read(buffer);
if (read == -1) {
key.cancel();
} catch (IOException e) {
e.printStackTrace();
key.cancel();
buffer.clear();
private static void client() {
selector = Selector.open();
for (int i = 0; i & 10; i++) {
SocketChannel client = SocketChannel.open();
client.configureBlocking(false);
client.connect(new InetSocketAddress("127.0.0.1", 8888));
client.register(selector, SelectionKey.OP_CONNECT);
} catch(IOException e) {
throw new RuntimeException(e);
ByteBuffer buffer = ByteBuffer.wrap(new byte[512]);
ByteBuffer read = ByteBuffer.allocate(512);
AtomicInteger sendCount = new AtomicInteger();
new Thread(()-&{
while(true) {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("sendCount = " + sendCount);
sendCount.set(0);
}).start();
while(true) {
selector.select();
} catch (IOException e) {
throw new RuntimeException(e);
for (Iterator&SelectionKey& iter = selector.selectedKeys().iterator(); iter.hasNext(); iter.remove()) {
SelectionKey key = iter.next();
SocketChannel sc = (SocketChannel) key.channel();
if (key.isConnectable()) {
sc.finishConnect();
} catch (IOException e) {
e.printStackTrace();
key.cancel();
key.interestOps(SelectionKey.OP_WRITE);
} else if (key.isWritable()) {
sc.write(buffer);
sendCount.incrementAndGet();
} catch (IOException e) {
key.cancel();
e.printStackTrace();
if(!buffer.hasRemaining()) {
buffer.flip();
} else if (key.isReadable()) {
if (-1 == sc.read(read)) {
key.cancel();
} catch (IOException e) {
e.printStackTrace();
key.cancel();
public static void main(String[] args) throws Exception {
Runnable server = NioTest::
Runnable client = NioTest::
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(server);
// wait server start up
TimeUnit.SECONDS.sleep(2);
executorService.execute(client);
--- 共有 2 条评论 ---
有c++的吗?
附上我的测试代码和结果:
#include&sys/types.h&
#include&sys/socket.h&
#include&netinet/in.h&
#include&arpa/inet.h&
#include&unistd.h&
#include &stdio.h&
#include &stdlib.h&
#include &strings.h&
#include&sys/wait.h&
#include &string.h&
#include &time.h&
#include &unistd.h&
#include &fcntl.h&
#include &sys/time.h&
#include &stdio.h&
&netinet/in.h&
#include &netinet/tcp.h& // for TCP_NODELAY
#include &sys/time.h&
#include &sys/epoll.h&
#include &time.h&
typedef unsigned int
void xsleep(uint32_t ms)
tval.tv_sec = ms / 1000;
tval.tv_usec = ( ms * 1000) % 1000000;
select(0, NULL, NULL, NULL, &tval);
int main(int argc, char ** argv)
int sockfd,new_
struct sockaddr_in my_
struct sockaddr_in their_
unsigned int sin_size, myport,
if(argv[1])
myport = atoi(argv[1]);
else myport = 50000;
if(argv[2])
lisnum = atoi(argv[2]);
else lisnum = 2;
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
printf("socket %d ok \n",myport);
//fcntl(sockfd, F_SETFL, O_NONBLOCK);
my_addr.sin_family=PF_INET;
my_addr.sin_port=htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 0);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
printf("bind ok \n");
if (listen(sockfd, lisnum) == -1) {
perror("listen");
printf("listen ok \n");
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
fcntl(new_fd, F_SETFL, O_NONBLOCK);
int arg = 1;
setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&arg, sizeof(int));
int nSendBuf=;//¨???32K
setsockopt(new_fd,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
struct epoll_event ev,events[20];
epfd=epoll_create(256);
ev.data.fd=
ev.events=EPOLLIN|EPOLLOUT;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);
ev.data.fd=new_
ev.events=EPOLLIN|EPOLLOUT;
epoll_ctl(epfd,EPOLL_CTL_ADD,new_fd,&ev);
szSnd[1024] = {0};
memset(szSnd,97,1024);
szSnd[100] = 0;
//time_t lasttime = time(NULL);
gettimeofday(&lasttime,0);
double alltimeuse = 0.0;
int iii = 0;
while(iii++&100)
gettimeofday(&lasttime,0);
if (send(new_fd, szSnd, strlen(szSnd), 0) == -1) {
perror("send");
struct timeval now_
gettimeofday(&now_time,0);
double timeuse = *(now_time.tv_sec - lasttime.tv_sec) + now_time.tv_usec - lasttime.tv_
timeuse /=1000.0;
printf("xxsend msg: %f\n",(timeuse));
gettimeofday(&lasttime,0);
if (send(new_fd, szSnd, strlen(szSnd), 0) == -1) {
perror("send");
struct timeval now_
gettimeofday(&now_time,0);
double timeuse = *(now_time.tv_sec - lasttime.tv_sec) + now_time.tv_usec - lasttime.tv_
timeuse /=1000.0;
printf("xxsend1 msg: %f\n",(timeuse));
for(int ccc=0; ccc&1000000; ccc++)
char aaax[10240];
memset(aaax,0,10240);
//xsleep(100);
//usleep(1000);
测试结果:可见第一次send很慢, 第二次send1很快, 如果while循环一直连续send就超快, 几十万次的确小意思, 但是一旦期间有其他代码执行下一次send就超慢, 在现实业务中肯定send完之后要做其他事情, 为何会这样?
socket 50000 ok
server: got connection from 192.168.125.69 xxsend msg: 0.327000 xxsend1 msg: 0.126000 xxsend msg: 0.058000 xxsend1 msg: 0.041000 xxsend msg: 0.028000 xxsend1 msg: 0.002000 xxsend msg: 0.929000 xxsend1 msg: 0.002000 xxsend msg: 0.045000 xxsend1 msg: 0.002000 xxsend msg: 0.068000 xxsend1 msg: 0.045000 xxsend msg: 0.054000 xxsend1 msg: 0.001000 xxsend msg: 0.044000 xxsend1 msg: 0.040000 xxsend msg: 0.029000 xxsend1 msg: 0.023000 xxsend msg: 3.455000 xxsend1 msg: 0.002000 xxsend msg: 0.050000 xxsend1 msg: 0.028000 xxsend msg: 0.061000 xxsend1 msg: 0.002000 xxsend msg: 0.049000 xxsend1 msg: 0.036000 xxsend msg: 0.179000 xxsend1 msg: 0.035000 xxsend msg: 0.048000 xxsend1 msg: 0.001000 xxsend msg: 0.058000 xxsend1 msg: 0.012000 xxsend msg: 0.053000 xxsend1 msg: 0.001000 xxsend msg: 0.065000 xxsend1 msg: 0.001000 xxsend msg: 0.030000 xxsend1 msg: 0.011000 xxsend msg: 0.151000 xxsend1 msg: 0.002000 xxsend msg: 0.059000 xxsend1 msg: 0.003000 xxsend msg: 0.054000 xxsend1 msg: 0.001000 xxsend msg: 0.053000 xxsend1 msg: 0.002000 xxsend msg: 0.047000 xxsend1 msg: 0.002000 xxsend msg: 0.045000 xxsend1 msg: 0.002000 xxsend msg: 0.118000 xxsend1 msg: 0.002000 xxsend msg: 0.143000 xxsend1 msg: 0.002000

参考资料

 

随机推荐