python实现TCP通讯
1.0 版本(备份)
import socket
from logUtils import log
from api import Api
def handle_client(client_socket, addr):
log.info(f"客户端的ip地址和端口号: {addr}")
try:
while True:
# 接收客户端发送的数据, 这次接收数据的最大字节数是1024
recv_data = client_socket.recv(1024)
if not recv_data:
# 如果没有接收到数据,说明客户端可能已经关闭了连接
break
# 对二进制数据进行解码
recv_content = recv_data #.decode("utf-8")
log.info(f'-----------------------------------------begin-------------------------------------')
log.info(f"接收客户端的数据为: {recv_content}")
api = Api()
send_data = api.Message_parsing(recv_data)
# 准备发送的数据
if send_data:
print(f'要发送的数据:{send_data}')
# send_data = b'h\x19\x00hK\x01\x00T\x07\x00\x02`\x00\x01\x00cE\x86A:3\x12\nXQ\x18\x10q!\x06{\x16'
# 发送数据给客户端
client_socket.send(send_data)
print('发送成功!')
log.info(f'-----------------------------------------end-------------------------------------')
except Exception as e:
print(f"处理客户端时发生错误: {e}")
log.info(f'-----------------------------------------error-------------------------------------')
finally:
# 关闭与客户端的套接字
client_socket.close()
print(f"与客户端 {addr} 的连接已关闭")
if __name__ == '__main__':
# 创建tcp服务端套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,让程序退出端口号立即释放
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 给程序绑定端口号
tcp_server_socket.bind(("0.0.0.0", 6999))
# 设置监听
tcp_server_socket.listen(128)
log.info("服务器开始监听端口号: 6999")
try:
while True:
# 等待客户端建立连接的请求
service_client_socket, ip_port = tcp_server_socket.accept()
log.info(f"客户端的IP地址和端口号: {ip_port}")
# 在单独的线程或进程中处理客户端连接,这里简化为直接调用处理函数
handle_client(service_client_socket, ip_port)
except KeyboardInterrupt:
print("服务器接收到停止信号,正在关闭...")
finally:
# 关闭服务端的套接字(通常在实际应用中,这一步会在所有客户端连接都关闭后执行,但在这里我们直接响应中断信号)
tcp_server_socket.close()
我想把他修改成可以服务端主动发报文的,进行了这样的操作:
import socket
from logUtils import log
from api import Api
def handle_client(client_socket, addr):
log.info(f"客户端的ip地址和端口号: {addr}")
# status = False
try:
while True:
api = Api()
# if status:
# print(f'04:\n20:插座启停')
# number = input("请输入你要调用的接口编号:")
#
# avtive_send_data , statu = api.get_active_send_data(str(number))
# status = statu
# if avtive_send_data:
# print(f'要发送的数据:{avtive_send_data}')
# # send_data = b'h\x19\x00hK\x01\x00T\x07\x00\x02`\x00\x01\x00cE\x86A:3\x12\nXQ\x18\x10q!\x06{\x16'
# # 发送数据给客户端
# client_socket.send(avtive_send_data)
# print('发送成功!')
# 接收客户端发送的数据, 这次接收数据的最大字节数是1024
recv_data = client_socket.recv(1024)
if not recv_data:
# 如果没有接收到数据,说明客户端可能已经关闭了连接
break
# 对二进制数据进行解码
recv_content = recv_data #.decode("utf-8")
log.info(f'-----------------------------------------begin-------------------------------------')
log.info(f"接收客户端的数据为: {recv_content}")
send_data = api.Message_parsing(recv_data)
# 准备发送的数据
if send_data:
log.info(f'要发送的数据:{send_data}')
print(f'要发送的数据:{send_data}')
# send_data = b'h\x19\x00hK\x01\x00T\x07\x00\x02`\x00\x01\x00cE\x86A:3\x12\nXQ\x18\x10q!\x06{\x16'
# 发送数据给客户端
client_socket.send(send_data)
log.info('发送成功!')
print('发送成功!')
log.info(f'-----------------------------------------end-------------------------------------')
except Exception as e:
log.info(f"处理客户端时发生错误: {e}")
print(f"处理客户端时发生错误: {e}")
log.info(f'-----------------------------------------error-------------------------------------')
finally:
# 关闭与客户端的套接字
client_socket.close()
print(f"与客户端 {addr} 的连接已关闭")
if __name__ == '__main__':
# 创建tcp服务端套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,让程序退出端口号立即释放
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 给程序绑定端口号
tcp_server_socket.bind(("0.0.0.0", 6999))
# 设置监听
tcp_server_socket.listen(128)
log.info("服务器开始监听端口号: 6999")
try:
while True:
# 等待客户端建立连接的请求
service_client_socket, ip_port = tcp_server_socket.accept()
log.info(f"客户端的IP地址和端口号: {ip_port}")
# 在单独的线程或进程中处理客户端连接,这里简化为直接调用处理函数
handle_client(service_client_socket, ip_port)
except KeyboardInterrupt:
print("服务器接收到停止信号,正在关闭...")
finally:
# 关闭服务端的套接字(通常在实际应用中,这一步会在所有客户端连接都关闭后执行,但在这里我们直接响应中断信号)
tcp_server_socket.close()
具体就是增加了一个状态变量,如果心跳了,就把状态设置成true,状态为true时,每次发送、接收报文都先判断一下是否需要主动发送。目前原理上感觉是可行的,我也写了一个测试的服务端-客户端,测试结果:可行。
但是这样子,在api.py里增加返回状态时,出现了报错。
具体是SIM卡上报信息是报错了:
cannot unpack non-iterable NoneType object
这个报错是对一个NoneType进行了数据操作,我找了半天也没找到SIM卡接口里有什么数据操作。
最后恢复一下代码,又能运行了。我再一步一步看看,到底是改了哪里出现了错误。
排查错误:
import socket
from logUtils import log
from api import Api
def handle_client(client_socket, addr):
log.info(f"客户端的ip地址和端口号: {addr}")
status = False
try:
while True:
api = Api()
if status:
print(f'04:\n20:插座启停')
number = input("请输入你要调用的接口编号:")
avtive_send_data , statu = api.get_active_send_data(str(number))
status = statu
if avtive_send_data:
print(f'要发送的数据:{avtive_send_data}')
# send_data = b'h\x19\x00hK\x01\x00T\x07\x00\x02`\x00\x01\x00cE\x86A:3\x12\nXQ\x18\x10q!\x06{\x16'
# 发送数据给客户端
client_socket.send(avtive_send_data)
print('发送成功!')
# 接收客户端发送的数据, 这次接收数据的最大字节数是1024
recv_data = client_socket.recv(1024)
if not recv_data:
# 如果没有接收到数据,说明客户端可能已经关闭了连接
break
# 对二进制数据进行解码
recv_content = recv_data #.decode("utf-8")
log.info(f'-----------------------------------------begin-------------------------------------')
log.info(f"接收客户端的数据为: {recv_content}")
send_data = api.Message_parsing(recv_data)
# 准备发送的数据
if send_data:
log.info(f'要发送的数据:{send_data}')
print(f'要发送的数据:{send_data}')
# send_data = b'h\x19\x00hK\x01\x00T\x07\x00\x02`\x00\x01\x00cE\x86A:3\x12\nXQ\x18\x10q!\x06{\x16'
# 发送数据给客户端
client_socket.send(send_data)
log.info('发送成功!')
print('发送成功!')
log.info(f'-----------------------------------------end-------------------------------------')
except Exception as e:
log.info(f"处理客户端时发生错误: {e}")
print(f"处理客户端时发生错误: {e}")
log.info(f'-----------------------------------------error-------------------------------------')
finally:
# 关闭与客户端的套接字
client_socket.close()
print(f"与客户端 {addr} 的连接已关闭")
if __name__ == '__main__':
# 创建tcp服务端套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,让程序退出端口号立即释放
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 给程序绑定端口号
tcp_server_socket.bind(("0.0.0.0", 6999))
# 设置监听
tcp_server_socket.listen(128)
log.info("服务器开始监听端口号: 6999")
try:
while True:
# 等待客户端建立连接的请求
service_client_socket, ip_port = tcp_server_socket.accept()
log.info(f"客户端的IP地址和端口号: {ip_port}")
# 在单独的线程或进程中处理客户端连接,这里简化为直接调用处理函数
handle_client(service_client_socket, ip_port)
except KeyboardInterrupt:
print("服务器接收到停止信号,正在关闭...")
finally:
# 关闭服务端的套接字(通常在实际应用中,这一步会在所有客户端连接都关闭后执行,但在这里我们直接响应中断信号)
tcp_server_socket.close()
把注释加回来,可以心跳。
func = Function_mapping[AFN].get(Fn)
log.info(f"接口匹配成功!")
data , status = func(dict_data)
log.info(f'type:{type(data)}')
return data, status
在接收数据这里加上status后,连登录都报错了。有两种报错
non-hexadecimal number found in fromhex() arg at position 63
too many values to unpack (expected 2):
这通常意味着你尝试将一个可迭代对象(如列表、元组等)解包到比该对象实际包含的元素数量更少的变量中。a, b = (1, 2, 3) # 这里会引发错误
意料之中,因为我还没修改函数返回值。
#先返回False,返回True后就会直接让输入接口编号了
return byte_resp_data, False
send_data , status = api.Message_parsing(recv_data)
# 准备发送的数据
if send_data:
log.info(f'要发送的数据:{send_data}')
print(f'要发送的数据:{send_data}')
# 发送数据给客户端
client_socket.send(send_data)
log.info('发送成功!')
print('发送成功!')
把登录和接收的数据修改后,可以成功登录了!
所以登录后的登录验证开始报错了,接下来把登录验证修改一下
return byte_resp_data, True
果然,修改后能成功进行登录验证了。
接下来试试能不能请求主动发送的接口。
试了一下,能发出去,但是收到的信息很。。。乱,SIM后面跟了两条心跳。
标签:log,info,socket,python,send,TCP,data,20240809,客户端 From: https://www.cnblogs.com/marverdol/p/18351248