首页 > 学院 > 开发设计 > 正文

socket长链接与短连接

2019-11-08 01:54:49
字体:
来源:转载
供稿:网友

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

心跳: 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 1024int 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;}


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表