登陆微博保持tcp链接吗
理论上来说是保持的。TCP连接,当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次握手的,而释放则需要4次握手,所以说每个连接的建立都是需要资源消耗和时间消耗的。TCP保活的必要性:TCP的长连接理论上只要连接建立后,就会一直保持着。但有时有一些防火墙之类的软件会自动检查主机的网络连接状况,比如说如果发现某个连接在几分钟之内都没有数据通讯,则会关闭这个连接。有时客户端与服务器需要实时的检测连接状态,就是需要知道对方是否还在线,如果对方不在线了,需要做相应的处理,这是就需要通过发送心跳包的方法监测链路的状态。导致 TCP 连接断连的因素 :理想状态下,一个 TCP 连接可以被长期保持。然而,在实际应用中,客户端或服务器端上维持的一个看似正常的 TTCP 连接可能已经断连。TCP 连接主要受到两个方面的影响而导致断连:网络中间节点和客户端 / 服务器节点参与通信的两方节点。在实际网络应用中,两个主机之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等。因此,两个主机之间 TCP 连接的保持同样会受到中间节点的影响,尤其是会受到防火墙(软件或硬件防火墙)的限制。防火墙是一种装置,有多种不同的实现方式(软件实现、硬件设备实现或是软硬件相结合实现),它需要依据一系列规则对进出的信息流进行扫描,并允许安全(符合规则)的信息交互、阻止不安全(违反规则)的信息交互。防火墙的工作特性决定了要维护一个网络连接就需要耗费较多的资源,并且企业防火墙常常位于企业网络的出入口,长时间维护非活跃的 TCP 连接必将导致网络性能的下降。因此,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 TCP 连接断连。类似的,如果中间节点异常导致如果中间节点异常导致来自客户端关闭连接的请求无法传递到服务器端,也将导致服务器端的相应连接发生断连。另一方面,对于一个 TCP 连接两端的主机而言,创建 TCP 连接需要耗费一定的系统资源。如果不再使用某个连接,那么我们总是希望进行通信的两个主机能够主动关闭相应的连接,以便释放所占用的系统资源。然而,如果由于客户端出现异常 ( 例如崩溃或异常重启 ) 而导致连接未能正常关闭,这将导致服务器端的连接断连。 无论是客户端节点或是服务器端节点,断连的 TCP 连接已经不能传递任何信息,因此,维护大量断连的 TCP 连接将导致系统资源的浪费。这种系统资源的浪费可能并不会对客户端节点带来太大问题;然而,对于服务器主机而言,这可能会导致系统资源(尤指内存资源和 socket 资源)被耗尽而拒绝为新的用户请求提供服务。因此在实际应用中,服务器端需要采取相应的方法来探测 TCP 连接是否已经断连。

TCP连接客户端的问题
这个是短连接模式,发完就断了。适用于不是非常频繁的信息交互。 如果发送的数据比较频繁,就要弄成长连接的模式,链路的保持是通过心跳包来实现的。也就是空闲的时候,双方或一方发送心跳包,保持链路的长期存在。
声明一个全局的网络连接对象,我一般用底层的Socket,既然你用TcpClient对象,也一样,你可以一直用这个对象,只进一次初始化连接,以后全部使用这个对象进行数据发送就行了,为了防止网络异常,或者发送失败,你需要定期检测TcpClient的连接状态,如果网络连接不正常时,偿试一下重新连接就行了,你最好封装成你需要的标准接口,不然,你这样写,后面的调试会乱,如果还有问题密我!
这个得看你的需求了,如果是用完就关就可以用你现在的方法。 如果是定时的或者不间段的发送数据,最好还是保持连接在线状态,根据需要进行数据传输;不过要注意发送前检查一下在线状态,在线了才能够发送成功 另外,进行TCP连接与数据发送时最好加上Try-catch-finally,防止传输过程中出现异常导致意外情况发生。。

如何进行tcp数据交互
这是我网络中找的参考,希望对你有帮助。 在多线程任务中,TCP任务通过三次握手能建立可靠的连接,但是经常会发生在数据传输或通信时发生网络突然断开或者长时间连接空循环监听而未进行操作,需要在软件设计时考虑程序运行中检测到服务器对客户端的这一“虚连接”现象。如果主机崩溃,write是否阻塞取决于内核的tcp缓冲区,但read将一直阻塞,直到超时ETIMEOUT,或由于某些中间路由器的原因返回EHOSTUNREACH/ENETUNREACH。select不能检测到该情况。如果主机崩溃并重起,客户的write到达主机时主机响应RST,客户的read将返ECONNRESET。此处的”非正常断开”指TCP连接不是以优雅的方式断开,如网线故障等物理链路的原因,还有突然主机断电等原因。心跳机制有两种方法可以检测:1.TCP连接双方定时发握手消息2.利用TCP协议栈中的KeepAlive探测第二种方法简单可靠,只需对TCP连接两个Socket设定KeepAlive探测,所以本文只讲第二种方法在Linux,Window2000下的实现(在其它的平台上没有作进一步的测试)1)Windows平台C代码//定义结构及宏struct TCP_KEEPALIVE {u_longonoff;u_longkeepalivetime;u_longkeepaliveinterval;} ;#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)//KeepAlive实现TCP_KEEPALIVE inKeepAlive = {0}; //输入参数unsigned long ulInLen = sizeof(TCP_KEEPALIVE);TCP_KEEPALIVE outKeepAlive = {0}; //输出参数unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);unsigned long ulBytesReturn = 0;//设置socket的keep alive为5秒,并且发送次数为3次inKeepAlive.onoff = 1;inKeepAlive.keepaliveinterval = 5000; //两次KeepAlive探测间的时间间隔inKeepAlive.keepalivetime = 5000; //开始首次KeepAlive探测前的TCP空闭时间if (WSAIoctl((unsigned int)s, SIO_KEEPALIVE_VALS,(LPVOID)&inKeepAlive, ulInLen,(LPVOID)&outKeepAlive, ulOutLen,&ulBytesReturn, NULL, NULL) == SOCKET_ERROR){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) WSAIoctl failed. error code(%d)!n"), WSAGetLastError()));}//定义结构及宏 struct TCP_KEEPALIVE { u_longonoff; u_longkeepalivetime; u_longkeepaliveinterval; } ; #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) //KeepAlive实现 TCP_KEEPALIVE inKeepAlive = {0}; //输入参数 unsigned long ulInLen = sizeof(TCP_KEEPALIVE); TCP_KEEPALIVE outKeepAlive = {0}; //输出参数 unsigned long ulOutLen = sizeof(TCP_KEEPALIVE); unsigned long ulBytesReturn = 0; //设置socket的keep alive为5秒,并且发送次数为3次 inKeepAlive.onoff = 1; inKeepAlive.keepaliveinterval = 5000; //两次KeepAlive探测间的时间间隔 inKeepAlive.keepalivetime = 5000; //开始首次KeepAlive探测前的TCP空闭时间 if (WSAIoctl((unsigned int)s, SIO_KEEPALIVE_VALS, (LPVOID)&inKeepAlive, ulInLen, (LPVOID)&outKeepAlive, ulOutLen, &ulBytesReturn, NULL, NULL) == SOCKET_ERROR) { ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) WSAIoctl failed. error code(%d)!n"), WSAGetLastError())); }2)Linux平台C代码#include……////KeepAlive实现//下面代码要求有ACE,如果没有包含ACE,则请把用到的ACE函数改成linux相应的接口int keepAlive = 1;//设定KeepAliveint keepIdle = 5;//开始首次KeepAlive探测前的TCP空闭时间int keepInterval = 5;//两次KeepAlive探测间的时间间隔int keepCount = 3;//判定断开前的KeepAlive探测次数if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt SO_KEEPALIVE error!n")));}if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPIDLE error!n")));}if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPINTVL error!n")));}if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t)setsockopt TCP_KEEPCNT error!n")));}心跳机制:定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性。网络中的接收和发送数据都是使用WINDOWS中的SOCKET进行实现。但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题。可是如何判断这个套接字是否还可以使用呢?这个就需要在系统中创建心跳机制。其实TCP中已经为我们实现了一个叫做心跳的机制。如果你设置了心跳,那TCP就会在一定的时间(比如你设置的是3秒钟)内发送你设置的次数的心跳(比如说2次),并且此信息不会影响你自己定义的协议。所谓“心跳”就是定时发送一个自定义的结构体(心跳包或心跳帧),让对方知道自己“在线”。以确保链接的有效性。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包。发包方:可以是客户也可以是服务端,看哪边实现方便合理。一般是客户端。服务器也可以定时轮询发心跳下去。心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项。系统默认是设置的是2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。心跳包一般来说都是在逻辑层发送空的包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀当然,这个自然是要由逻辑层根据需求去做了。总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。TCP连接异常断开后操作系统会告诉你,你查询套接字的状态会得到异常,或者当发现函数失败WSAGetLastError的时候也会得到内核的通知。// 发送回应消息int nSend = Send4IntMsg(sock, (char*)(LPCTSTR)strSendBuf,strSendBuf.GetLength(), errMsg);if (nSend < 0) //发送消息失败closesocket(sock);//重新连接 在B/S编程和UDP编程时才用到心跳。比如定期向web服务器发一个request证明自己在线。http协议是请求一下就断开了,每次都要重新连接,重新请求,这种情况下才有必要用心跳机制。一般的TCP通信都是长连接,不可能频繁连接和断开。对于长期保持连接的情况,一旦断开,操作系统底层都会通知你,你需要解决的是如何获取到系统的通知。

TCP通讯怎么连接到外网的服务器
你好,很高兴为你解答! 根据你的描述,只要你的服务器IP地址是公网的,就可以直接连,服务器一般放置在公网上,有固定的IP地址。 希望我的回答可以帮助你,安徽电信祝您生活愉快。

QQ是一个基于TCP/UDP协议的通讯软件
原文地址: http://f543711700.iteye.com/blog/978044发送消息的时候是UDP打洞,登陆的时候使用HTTP~因为登陆服务器其实就是一个HTTP服务器,只不过不是常用的那些,那个服务器是腾讯自行开发的!!!QQ客户端在局域网内,当你打开QQ登录到QQ服务器时,通过外网,你的客户端与QQ服务器建立了一个长连接。你可以用netstat -bn看到此连接的状态是 establish此时,在QQ服务器那面看到的连接的IP是你们局域网对外的IP。举个例子:这是一个假象。通过QQ服务器看到的连接是:这样,防火墙上的31234口对应的就是你机器的55579口。(由于你是发起方,这个数是变化的。动态的)当有信息给你时,QQ服务器只需要发给防火墙的55579口即可。(这里防火墙作了地址翻译)不管UDP还是TCP,最终登陆成功之后,QQ都会有一个TCP连接来保持在线状态。这个TCP连接的远程端口一般是80,采用UDP方式登陆的时候,端口是8000。因此,假如你所在的网络开放了80端口(80端口是最常用端口。。就是通常访问Web的端口,禁掉它的话,你的网络对你来说价值已经不大了),但没有屏蔽腾讯的服务器IP,恭喜你,你是可以登陆成功QQ的。采用UDP协议,通过服务器中转方式。大家都知道,UDP 协议是不可靠协议,它只管发送,不管对方是否收到的,但它的传输很高效。但是,作为聊天软件,怎么可以采用这样的不可靠方式来传输消息呢?于是,腾讯采用了上层协议来保证可靠传输:如果客户端使用UDP协议发出消息后,服务器收到该包,需要使用UDP协议发回一个应答包。如此来保证消息可以无遗漏传输。之所以会发生在客户端明明看到“消息发送失败”但对方又收到了这个消息的情况,就是因为客户端发出的消息服务器已经收到并转发成功,但客户端由于网络原因没有收到服务器的应答包引起的。因为用户一般都是在局域网内,地址都为私有IP,腾讯服务器是如何将信息转发到用户的?首先先介绍一些基本概念:最先提出的是基本的NAT,它的产生基于如下事实:一个私有网络(域)中的节点中只有很少的节点需要与外网连接(呵呵,这是在上世纪90年代中期提出的)。那么这个子网中其实只有少数的节点需要全球唯一的IP地址,其他的节点的IP地址应该是可以重用的。因此,基本的NAT实现的功能很简单,在子网内使用一个保留的IP子网段,这些IP对外是不可见的。子网内只有少数一些IP地址可以对应到真正全球唯一的IP地址。如果这些节点需要访问外部网络,那么基本NAT就负责将这个节点的子网内IP转化为一个全球唯一的IP然后发送出去。(基本的NAT会改变IP包中的原IP地址,但是不会改变IP包中的端口)关于基本的NAT可以参看RFC 1631另外一种NAT叫做NAPT,从名称上我们也可以看得出,NAPT不但会改变经过这个NAT设备的IP数据报的IP地址,还会改变IP数据报的TCP/UDP端口。基本NAT的设备可能我们见的不多(呵呵,我没有见到过),NAPT才是我们真正讨论的主角。看下图:有一个私有网络10. . .*,ClientA是其中的一台计算机,这个网络的网关(一个NAT设备)的外网IP是155.99.25.11(应该还有一个内网的IP地址,比如10.0.0.10)。如果Client A中的某个进程(这个进程创建了一个UDPSocket,这个Socket绑定1234端口)想访问外网主机18.181.0.31的1235端口,那么当数据包通过NAT时会发生什么事情呢?首先NAT会改变这个数据包的原IP地址,改为155.99.25.11。接着NAT会为这个传输创建一个Session(Session是一个抽象的概念,如果是TCP,也许Session是由一个SYN包开始,以一个FIN包结束。而UDP呢,以这个IP的这个端口的第一个UDP开始,结束呢,呵呵,也许是几分钟,也许是几小时,这要看具体的实现了)并且给这个Session分配一个端口,比如62000,然后改变这个数据包的源端口为62000。所以本来是(10.0.0.1:1234->18.181.0.31:1235)的数据包到了互联网上变为了(155.99.25.11:62000->18.181.0.31:1235)。一旦NAT创建了一个Session后,NAT会记住62000端口对应的是10.0.0.1的1234端口,以后从18.181.0.31发送到62000端口的数据会被NAT自动的转发到10.0.0.1上。(注意:这里是说18.181.0.31发送到62000端口的数据会被转发,其他的IP发送到这个端口的数据将被NAT抛弃)这样Client A就与Server S1建立以了一个连接。呵呵,上面的基础知识可能很多人都知道了,那么下面是关键的部分了。看看下面的情况:接上面的例子,如果Client A的原来那个Socket(绑定了1234端口的那个UDP Socket)又接着向另外一个Server S2发送了一个UDP包,那么这个UDP包在通过NAT时会怎么样呢?这时可能会有两种情况发生,一种是NAT再次创建一个Session,并且再次为这个Session分配一个端口号(比如:62001)。另外一种是NAT再次创建一个Session,但是不会新分配一个端口号,而是用原来分配的端口号62000。前一种NAT叫做SymmetricNAT,后一种叫做ConeNAT。我们期望我们的NAT是第二种,呵呵,如果你的NAT刚好是第一种,那么很可能会有很多P2P软件失灵。(可以庆幸的是,现在绝大多数的NAT属于后者,即Cone NAT)好了,我们看到,通过NAT,子网内的计算机向外连结是很容易的(NAT相当于透明的,子网内的和外网的计算机不用知道NAT的情况)。但是如果外部的计算机想访问子网内的计算机就比较困难了(而这正是P2P所需要的)。那么我们如果想从外部发送一个数据报给内网的计算机有什么办法呢?首先,我们必须在内网的NAT上打上一个“洞”(也就是前面我们说的在NAT上建立一个Session),这个洞不能由外部来打,只能由内网内的主机来打。而且这个洞是有方向的,比如从内部某台主机(比如:192.168.0.10)向外部的某个IP(比如:219.237.60.1)发送一个UDP包,那么就在这个内网的NAT设备上打了一个方向为219.237.60.1的“洞”,(这就是称为UDP HolePunching的技术)以后219.237.60.1就可以通过这个洞与内网的192.168.0.10联系了。(但是其他的IP不能利用这个洞)。呵呵,现在该轮到我们的正题P2P了。有了上面的理论,实现两个内网的主机通讯就差最后一步了:两边都无法主动发出连接请求,谁也不知道谁的公网地址,那我们如何来打这个洞呢?我们需要一个中间人来联系这两个内网主机。现在我们来看看一个P2P软件的流程,以下图为例:首先,Client A登录服务器,NAT A为这次的Session分配了一个端口60000,那么ServerS收到的Client A的地址是202.187.45.3:60000,这就是Client A的外网地址了。同样,ClientB登录Server S,NAT B给此次Session分配的端口是40000,那么ServerS收到的B的地址是187.34.1.56:40000。此时,Client A与Client B都可以与ServerS通信了。如果Client A此时想直接发送信息给Client B,那么他可以从ServerS那儿获得B的公网地址187.34.1.56:40000,是不是Client A向这个地址发送信息ClientB就能收到了呢?答案是不行,因为如果这样发送信息,NATB会将这个信息丢弃(因为这样的信息是不请自来的,为了安全,大多数NAT都会执行丢弃动作)。那该怎么办呢? 首先我们假设Server S是219.237.60.1:7000,当Clinet A(202.187.45.3:60000)向Server S(219.237.60.1:7000)发送数据包,Server S是可以正常接收到数据,因为它是属于外型开放的服务器端口。当Server S收到数据包后可以获知Clinet A(202.187.45.3:60000)对外通信的临时session信息(这个叫临时的端口,假设是60000会过期,具体时间不同,一般是每30S发送一个keep住连接以保证端口维持通信连接不断)Server S此时应将次信息保存起来。而同时,Client B (192.168.0.10:40000)也在时刻向Server S发送心跳包,Server S就向Client B (192.168.0.10:40000)发送一个通知,让Client B(192.168.0.10:4000) 发送探测包(这个数据包最好发几个),Client B(192.168.0.10:4000)在收到通知后在向Server S发送反馈包,说明以向自己以向Client A(192.168.0.20:60000)发送了探测包,Server S在收到反馈之后再向Client A(192.168.0.20:60000)转发反馈包,Client A(192.168.0.20:60000)在收到数据包之后在向原本要求请求的Client B(192.168.0.10:4000)发送数据包,此时连接已经打通,实现穿透。Client B(192.168.0.10:4000)会将数据包转发给Client A(192.168.0.20:60000)从而在转发给内网内网IP:192.168.0.1。 对于Symmetric NAPT的情况,网上有人说可以通过探测端口的方式,不过成功率并不高,我建议可用服务器进行中转。另外,最好在数据包发送前先检测是否进行的是同个NAT的情况,也就是内网发内网,如果是,直接发送即可,而无需通过外网再绕回来。

本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/47410.html。