TCP socket如何判断连接断开
分类:计算机教程

自己做了一个tcp工具,在学习动画的时候踩了坑,需求是根据上线变绿色,离线变灰色,如果连接断开了,则变为灰色

http://blog.csdn.net/zzhongcy/article/details/21992123

问题现象:

美洲杯赔率,SO_KEEPALIVE是系统底层的机制,用于系统维护每一个tcp连接的。

美洲杯赔率 1

心跳线程属于应用层,主要用于终端和服务器连接的检查。

可以看到点击“连接”,“离线”的时候动画是正常的,但是当tcp超时断开后,虽然离线按钮变为连接了,却没有执行离线动画

即使SO_KEEPALIVE检测到连接正常,但并不能保证终端和服务器连接的正常。有一种情况,服务器进程死了,但它和客户端的tcp连接还连着(该连接由系统维护的)。

关键源代码如下

这就是SO_KEEPALIVE不能取代心跳线程的原因吧。

class BSJTcpThread(QtCore.QThread):
  recv_signal = QtCore.pyqtSignal(str)
  send_signal = QtCore.pyqtSignal(str)

  def __init__(self, socketcp, onBtn, heartcheck, senBtn, scene):
    super().__init__()
    self.s = socketcp
    self.yqtool = Bianlifunction()
    self.onBtn = onBtn
    self.heartcheck = heartcheck
    self.sendBtn = senBtn
    self.scene1 = scene

  def run(self):
    """线程"""
    global stopsingle
    stopsingle = 0
    while 1:
      btcpreceive = self.s.recv(1024)
      tcpreceive1 = str(binascii.b2a_hex(btcpreceive), encoding="utf-8")

      tcpreceive = ""
      i = 0
      while i < len(tcpreceive1) - 1: # 十六进制数据处理,两个字节隔开
        if i == len(tcpreceive1) - 2:
          tcpreceive  = tcpreceive1[i:i   2]
          i  = 2
        else:
          tcpreceive  = tcpreceive1[i:i   2]   " "
          i  = 2

      if tcpreceive == "":
        stopsingle = 1
        self.s.shutdown(2)
        self.s.close()
        self.onBtn.setText("连接")
        self.scene1.offlineCol.start() # 启动离线动画
        self.heartcheck.setChecked(False)
        self.heartcheck.setVisible(False)
        self.sendBtn.setDisabled(True)
      else:
        self.recv_signal.emit(tcpreceive)
      if stopsingle == 1:
        break

 

然后再启动线程

 

      self.tcpth = BSJTcpThread(self.s, self.onBtn, self.heartcheck, self.sendBtn, self.scene)
      self.tcpth.recv_signal.connect(self.fillrecvmsg)
      self.tcpth.send_signal.connect(self.fillsendmsg)
      self.tcpth.start()

###############################

问题点:

     最近在做一个TCP采集程序,使用到C/S的结构。功能比较的简单,就是TCP采集程序作为服务器,信令采集设备作为客户端,客户端与服务器端之间建立长连接之后,开始发送信令报文给服务器。在服务器端使用多线程方式来处理每个客户端的socket连接,服务器端不主动断开链路,也没有心跳机制来维护连接的状态,客户端发送数据的时间也是不一定的,只要有采集到信令数据时才进行发送。在客户端socket断开后,服务器端应该能够知道并且释放socket资源。
     判断socket是否已经断开的方法是使用非阻塞的select方式进行socket检查,步骤如下:

经过谷爹搜索,终于找到了问题原因详见https://stackoverflow.com/questions/44328750/pyqt-qgraphicscene-move-item-in-background-thread

1)设置接收到的socket为异步方式;

大致原因就是QGraphics Scene 不是一个安全的线程对象,我们不能直接在线程中去改变主程序的状态,我们必须通过信号的方式去更新QGraphics

2)使用select()函数测试一个socket是否可读;

解决方法:

3)如果select()函数返回的值为1,但是使用recv()函数读取的数据长度为0,那么说明该socket已经断开。

首先,我们编辑一个信号方法

4)如果recv()返回值小于等于0时,客户端的连接已经断开,但是还需要判断errno是否等于EINTR。如果errno=EINTR则说明recv()函数是由于程序接收到中断信号后返回的,socket连接应该还是正常,步应该close掉socket连接

  def threadAnimate(self, message):
    if message == "1":
      self.scene.offlineCol.start()

 

然后添加相关信号槽

注:对于阻塞socket的recv函数会在以下三种情况下返回值:

self.tcpth = BSJTcpThread(self.s, self.onBtn, self.heartcheck, self.sendBtn)
      self.tcpth.recv_signal.connect(self.fillrecvmsg)
      self.tcpth.send_signal.connect(self.fillsendmsg)
      self.tcpth.animate_signal.connect(self.threadAnimate) # 添加一个动画信号
      self.tcpth.start()

1)接收到数据时会返回;

在线程中发出离线动画的信号

2)程序接收到信号时返回-1,errno=EINTR;

本文由美洲杯赔率发布于计算机教程,转载请注明出处:TCP socket如何判断连接断开

上一篇:golang新手们容易犯的3个错误总结 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • TCP socket如何判断连接断开
    TCP socket如何判断连接断开
    自己做了一个tcp工具,在学习动画的时候踩了坑,需求是根据上线变绿色,离线变灰色,如果连接断开了,则变为灰色 http://blog.csdn.net/zzhongcy/article/detail
  • golang新手们容易犯的3个错误总结
    golang新手们容易犯的3个错误总结
    这是因为golang中变量的作用域范围小到每个词法块(不理解的同学可以简单的当成{}包裹的部分)都是一个单独的作用域,大家都知道每个作用域的内部声
  • [转载]SQL语句中的日期计算美洲杯赔率:
    [转载]SQL语句中的日期计算美洲杯赔率:
    本月的第一天 SELECT  DATEADD(mm,  DATEDIFF(mm,0,getdate()),  0)  本月的最后一天 SELECT  dateadd(ms,-3,DATEADD(mm,  DATEDIFF(m,0,getdate()) 1, 0))  3.上个月的第一天 select da
  • MySQL自增列(AUTO_INCREMENT)相关知识点总结
    MySQL自增列(AUTO_INCREMENT)相关知识点总结
      MySQL的自增列(AUTO_INCREMENT)和其它数据库的自增列对比,有很多特性和不同点(甚至不同存储引擎、不同版本也有一些不同的特性),让人感觉有点稍微
  • 应用canvas绘制动态时钟--每秒自动动态更新时间,
    应用canvas绘制动态时钟--每秒自动动态更新时间,
    使用canvas绘制时钟 下文是部分代码,完整代码参照: https://github.com/lemoncool/canvas-clock ,可直接下载。 首先看一下效果图:每隔一秒会动态更新时间 一、前