socket长链接与短连接

2/22/2017来源:ASP.NET技巧人气:3782

长链接------------------

心跳:  socket模拟网页的报文连接某个网站,创建tcp的socket后,当我socket.connect后,如果在5到7秒钟不socket.send,那么这个链接就失效了。 请问如何长时间的保持这个链接  这是在服务器端的设置的,客户端没法设置,可以发送心跳包。  socket.connect后,每3-4秒用socket.send发送一字节数据(内容随便),然后观查这个连接是否保持。  lientSocket=serverSocket.accept();  OutputStream os = clientSocket.getOutputStream();            ObjectOutputStream oos=new ObjectOutputStream(os);  oos.writeObject(al);  oos.flush();  oos.close()//socket会关闭  实现:  长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。  如果,长时间未发送维持连接包,服务端程序将断开连接。  客户端:  通过持有Client对象,可以随时(使用sendObject方法)发送Object给服务端。  如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则,自动发送一个KeepAlive对象给服务端,  用于维持连接。  由于,我们向服务端,可以发送很多不同的对象,服务端也可以返回不同的对象。  所以,对于返回对象的处理,要编写具体的ObjectAction实现类进行处理。  通过Client.addActionMap方法进行添加。这样,程序会回调处理。  服务端:  由于客户端会定时(keepAliveDelay毫秒)发送维持连接的信息过来,所以,服务端要有一个检测机制。  即当服务端receiveTimeDelay毫秒(程序中是3秒)内未接收任何数据,则,自动断开与客户端的连接。 

长连接与短连接的操作过程  通常的短连接操作步骤是:    连接→数据传输→关闭连接; 而长连接通常就是:    连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接;  这就要求长连接在没有数据通信时,定时发送数据包(心跳),以维持连接状态, 短连接在没有数据传输时直接关闭就行了 什么时候用长连接,短连接? 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。 每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多, 所以每个操作完后都不断开,下次次处理时直接发送数据包就OK了,不用建立TCP连接。

方法1:应用层自己实现的心跳包  由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个低级别的线程,在该线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线;同样,如果客户端在一定时间内没 有收到服务器的心跳包,则认为连接不可用。 方法2:TCP的KeepAlive保活机制 因为要考虑到一个服务器通常会连接多个客户端,因此由用户在应用层自己实现心跳包,代码较多 且稍显复杂,而利用TCP/ip协议层为内置的KeepAlive功能来实现心跳功能则简单得多。 不论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。 因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不开启KeepAlive功 能,尽管这微不足道,但在按流量计费的环境下增加了费用,另一方面,KeepAlive设置不合理时可能会 因为短暂的网络波动而断开健康的TCP连接。并且,默认的KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多服务端应用程序来说,2小时的空闲时间太长。因此,我们需要手工开启KeepAlive功能并设置合理的KeepAlive参数。 以上转自网络。 心跳包机制   跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。    在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。    心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。    其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。    在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。    总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。 心跳检测步骤: 1客户端每隔一个时间间隔发生一个探测包给服务器 2客户端发包时启动一个超时定时器 3服务器端接收到检测包,应该回应一个包 4如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器 5如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了 、一个最简单的长连接与心跳保持的示例程序 /*!  ******************************************************************************  ******************************************************************************  */ #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <resolv.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #define MAXBUF 1024 int main(int argc, char **argv) {   int sockfd, len;   struct sockaddr_in dest;   char buffer[MAXBUF];   char heartbeat[20] = "hello server";   fd_set rfds;   struct timeval tv;   int retval, maxfd = -1;   if (argc != 3)   {     PRintf("error! the right format should be : \           \n\t\t%s IP port\n\t eg:\t%s127.0.0.1 80\n",           argv[0], argv[0]);     exit(0);   }   if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)   {     perror("Socket");     exit(errno);   }   bzero(&dest, sizeof(dest));   dest.sin_family = AF_INET;   dest.sin_port = htons(atoi(argv[2]));   memset(&(dest.sin_zero), 0, 8);   if (inet_aton(argv[1], (struct in_addr*)&dest.sin_addr.s_addr) == 0)   {     perror(argv[1]);     exit(errno);   }   if (connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0)   {     perror("Connect");     exit(errno);   }   printf("\nReady to start chatting.\n\         Direct input messages and \n\         enter to send messages to the server\n");   while (1)   {     FD_ZERO(&rfds);     FD_SET(0, &rfds);     maxfd = 0;     FD_SET(sockfd, &rfds);     if (sockfd > maxfd)       maxfd = sockfd;     tv.tv_sec = 2;     tv.tv_usec = 0;     retval = select(maxfd+1, &rfds, NULL, NULL, &tv);     if (retval == -1)     {       printf("Will exit and the select is error! %s", strerror(errno));       break;     }     else if (retval == 0)     {       //printf("No message comes, no buttons, continue to wait ...\n");       len = send(sockfd, heartbeat, strlen(heartbeat), 0);       if (len < 0)       {         printf("Message '%s' failed to send ! \               The error code is %d, error message '%s'\n",               heartbeat, errno, strerror(errno));         break;       }       else       {         printf("News: %s \t send, sent a total of %d bytes!\n",               heartbeat, len);       }       continue;     }     else     {       if (FD_ISSET(sockfd, &rfds))       {         bzero(buffer, MAXBUF+1);         len = recv(sockfd, buffer, MAXBUF, 0);         if (len > 0)         {           printf("Successfully received the message: '%s',%d bytes of data\n",                   buffer, len);         }         else         {           if (len < 0)               printf("Failed to receive the message! \                     The error code is %d, error message is '%s'\n",                     errno, strerror(errno));           else               printf("Chat to terminate!\n");           break;         }       }       if (FD_ISSET(0, &rfds))       {         bzero(buffer, MAXBUF+1);         fgets(buffer, MAXBUF, stdin);         if (!strncasecmp(buffer, "quit", 4))         {           printf("Own request to terminate the chat!\n");           break;         }         len = send(sockfd, buffer, strlen(buffer)-1, 0);         if (len < 0)         {           printf("Message '%s' failed to send ! \                 The error code is %d, error message '%s'\n",                 buffer, errno, strerror(errno));           break;         }         else         {           printf("News: %s \t send, sent a total of %d bytes!\n",                 buffer, len);         }       }     }   }   close(sockfd);   return 0; }