关于socket的问题 “recv()函数 超时”

来源:10-2 socket 和 server 实现通信

shuaiDevelop

2019-08-23

老师,我请教一个关于socket的问题:
socket监听本地一个端口 与远程的硬件设备进行通信,发送指令并接收数据。遇到的问题是,在 data = conn.recv(1024) 接收数据,有时候(不定时)会出现 Timeout错误 ( [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败),导致程序异常退出。 捕获异常后 程序依然会退出图片描述
图片描述
图片描述

写回答

2回答

shuaiDevelop

提问者

2019-08-29

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
import threading
import binascii
import time
from jpype import *
import os.path
import pymysql
import re

"""1、 pip install JPype1-py3
   2、 保证系统安装java环境 且java位数与python位数相等
   3、 jar包与py文件处于同一目录
   4、 pip install pymysql
"""

jar_path = os.path.join(os.path.abspath('.'), 'HexToTen.jar')
data_count = 0


def tcplink(conn, addr, mysql_conn, mysql_cursor):

    print("Accept new connection from %s:%s" % addr)
    global data_count
    while True:

        try:
            time.sleep(2)

            data_count += 1

            data = conn.recv(1024)

            if not data or len(data) <= 0:
                break

            d = binascii.b2a_hex(data)

            print('原始数:')
            print(data)
            # print(type(data))
            s = str(d, encoding="utf-8")
            if s == '31':
                print('心跳包')
            print('转换后:')
            print(s)

            send_str = "030390000006E92A"
            send_bytes = bytes.fromhex(send_str)
            conn.send(send_bytes)
            print('蒙西发送03:')
            print(send_bytes)



            if not isJVMStarted():
                startJVM(getDefaultJVMPath(), "-ea", "-Djava.class.path=%s" % jar_path)

            Test = JClass('gnkjtest.HexToTen')
            # print(Test.HexToTenFloat("43A4B50D"))

            temp_str = str.upper(s)
            try:
            # 03 03 0c 8cc1e449 3a750f44 e1553e40 8510

                # 每间隔34位进行取数 根据返回值固定 03030c8cc1e4493a750f44e1553e408510
                interval_temp_str = 34

                temp_list = [temp_str[i:i+interval_temp_str] for i in range(0, len(temp_str), interval_temp_str)]

                for t_str in temp_list:
                    if len(t_str) >= interval_temp_str :
                        data_type = temp_str[0:2]

                        if bool(re.search('[a-zA-Z]', data_type)):
                            continue

                        # 每隔 2 为取一次 蒙西规则 8位16进制 2位需要逆序解析 8cc1e449 :49e4c18c
                        temp_interval_t_str = 2
                        temp_t_str_list = [t_str[i:i + temp_interval_t_str] for i in
                                     range(0, len(t_str), temp_interval_t_str)]

                        # 传递给java进行16进制解析
                        lei_ji_i = Test.HexToTenFloat(temp_t_str_list[6] + temp_t_str_list[5] + temp_t_str_list[4] + temp_t_str_list[3])
                        liu_liang_f = Test.HexToTenFloat(temp_t_str_list[10] + temp_t_str_list[9] + temp_t_str_list[8] + temp_t_str_list[7])
                        su_du_f = Test.HexToTenFloat(temp_t_str_list[14] + temp_t_str_list[13] + temp_t_str_list[12] + temp_t_str_list[11])


                        # 解析后 转字符串准备存库
                        lei_ji_sql = str(lei_ji_i)
                        liu_liang_sql = str(liu_liang_f)
                        su_du_sql = str(su_du_f)

                        print("编号: %s; 累计:%s;  流量: %s;  速度:%s" % (
                            data_type, lei_ji_sql,  liu_liang_sql, su_du_sql))


                        sql_insert = "INSERT INTO BELT_SCALE_DATA(GRANDTOTAL, FLOW, SPEED, DEVICEID) VALUES (%s, %s, %s, %s);"

                        sql_insert_real = "INSERT INTO BELT_SCALE_DATA_REAL(GRANDTOTAL, FLOW, SPEED, DEVICEID) VALUES (%s, %s, %s, %s);"

                        sql_update_real = "UPDATE BELT_SCALE_DATA_REAL SET GRANDTOTAL=%s, FLOW=%s, SPEED=%s WHERE DEVICEID=%s;"

                        sql_select_real = "SELECT COUNT(*) FROM BELT_SCALE_DATA_REAL WHERE DEVICEID=%s;"

                        try:

                            mysql_cursor.execute(sql_select_real, [data_type])
                            ret = mysql_cursor.fetchone()
                            # 查询到数据 就更新 否则插入一条
                            if ret[0] >= 1:
                                mysql_cursor.execute(sql_update_real,
                                                     [lei_ji_sql, liu_liang_sql, su_du_sql,
                                                      data_type])
                            else:
                                mysql_cursor.execute(sql_insert_real,
                                                     [lei_ji_sql, liu_liang_sql, su_du_sql,
                                                      data_type])

                            #  1秒存4条  小于60s 更新到实时表 大于60s存历史表
                            if data_count >= 60:
                                mysql_cursor.execute(sql_insert,
                                                     [lei_ji_sql, liu_liang_sql, su_du_sql,
                                                      data_type])

                            mysql_conn.commit()


                        except Exception as e:
                            print("处理mysql出错")
                            print(e)
                            mysql_conn.rollback()


            except Exception as e:
                print("数据解析出错")
                print(e)

            # 计数间隔 清0
            if data_count >= 60:
                data_count = 0

            if data == b"exit":
                conn.send(b"Good bye!\n")
                conn.shutdown(socket.SHUT_RDWR)
                conn.close()
                shutdownJVM()
                break
        except Exception as e:
            print(e)
            print("While 循环内部 出现异常、、")
            break
        # shutdownJVM()

    conn.shutdown(socket.SHUT_RDWR)
    conn.close()
    shutdownJVM()
    #mysql_cursor.close()
    #mysql_conn.close()
    print("Connection from %s:%s is closed" % addr)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(("192.168.4.8", 5004))

s.listen(5)
print("Waiting for connection...")
mysql_conn = pymysql.connect(host="127.0.0.1", user="root", password="Gnkj123456", database="scales_data",
                             charset="utf8")
mysql_cursor = mysql_conn.cursor()
print("mysql 数据库已连接")

while True:

    try:
        conn, addr = s.accept()
        t = threading.Thread(target=tcplink, args=(conn, addr, mysql_conn, mysql_cursor))
        t.start()
    except Exception as e:
        print(e)


0
0

bobby

2019-08-27

远程设备是一个随时处于连接状态的服务器吗?

0
4
shuaiDevelop
回复
bobby
老师,我把我的代码在回答里编辑了一份,有空帮忙看下,水平不够 不知道是不是逻辑啥的出现了问题
2019-08-29
共4条回复

Python3高级核心技术97讲,高级进阶的必学课程

socket编程/多线程/多进程/线程池/asyncio并发编程/协程和异步IO

2121 学习 · 551 问题

查看课程