繁体   English   中英

Python3套接字,套接字接收时出现随机的部分结果

[英]Python3 socket, random partial result on socket receive

我已经使用Python套接字编写了基本的客户端/服务器接口(仅引用了代码的相关部分以获取完整脚本:(服务器: https : //github.com/mydomo/ble-presence/blob/master/server.py ) (客户: https : //github.com/mydomo/ble-presence/blob/master/clients/DOMOTICZ/ble-presence/plugin.py

问题是,当脚本从几个小时开始运行并且结果列表越来越大时,有时回复完全如期,其他时候它被剪切,没有完成...这是随机的,例如套接字无缘无故地关闭或答复未完全阅读。

你能帮我么?

服务器:

def client_thread(conn, ip, port, MAX_BUFFER_SIZE = 32768):
    # the input is in bytes, so decode it
    input_from_client_bytes = conn.recv(MAX_BUFFER_SIZE)

    # MAX_BUFFER_SIZE is how big the message can be
    # this is test if it's too big
    siz = sys.getsizeof(input_from_client_bytes)
    if  siz >= MAX_BUFFER_SIZE:
        print("The length of input is probably too long: {}".format(siz))

    # decode input and strip the end of line
    input_from_client = input_from_client_bytes.decode("utf8").rstrip()

    res = socket_input_process(input_from_client)
    #print("Result of processing {} is: {}".format(input_from_client, res))

    vysl = res.encode("utf8")  # encode the result string
    conn.sendall(vysl)  # send it to client
    conn.close()  # close connection
##########- END FUNCTION THAT HANDLE SOCKET'S TRANSMISSION -##########

def start_server():
    global soc
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # this is for easy starting/killing the app
    soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    #print('Socket created')
    try:
        soc.bind((socket_ip, socket_port))
    #    print('Socket bind complete')
    except socket.error as msg:
    #    print('Bind failed. Error : ' + str(sys.exc_info()))
        sys.exit()


    #Start listening on socket
    soc.listen(10)
    #print('Socket now listening')

    # for handling task in separate jobs we need threading
    #from threading import Thread

    # this will make an infinite loop needed for
    # not reseting server for every client
    while (not killer.kill_now):
        conn, addr = soc.accept()
        ip, port = str(addr[0]), str(addr[1])
        #print('Accepting connection from ' + ip + ':' + port)
        try:
            Thread(target=client_thread, args=(conn, ip, port)).start()
        except:
            print("Terible error!")
            import traceback
            traceback.print_exc()
soc.close()

客户:

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
SERV_ADDR = str(Parameters["Address"])
SERV_PORT = int(Parameters["Port"])
soc.connect((SERV_ADDR, SERV_PORT))

if BATTERY_REQUEST == True:
    clients_input = str(BATTERY_DEVICE_REQUEST)
else:
    clients_input = "beacon_data"

soc.send(clients_input.encode()) # we must encode the string to bytes  
result_bytes = soc.recv(32768) # the number means how the response can be in bytes  
result_string = result_bytes.decode("utf8") # the return will be in bytes, so decode

方法recv()不能保证在第一次调用中会收到完整的消息,因此您必须尝试通过多次调用recv()来获取完整的消息。
如果recv()确实返回空字符串,则在客户端关闭连接。

使用此while循环,您可以将客户端的完整流转换为data

data = b''  # recv() does return bytes
while True:
    try:
        chunk = conn.recv(4096)  # some 2^n number
        if not chunk:  # chunk == ''
            break

        data += chunk

    except socket.error:
        conn.close()
        break

TCP是一种流协议,这意味着它不构成完整消息的概念。 您必须在TCP之上实现自己的消息协议层,以确保发送和接收完整的消息。 您负责缓冲收到的数据,直到收到完整的消息,并且您必须定义什么是完整的消息。 一些选项:

  1. 发送固定长度的消息。
  2. 发送固定数量的字节,代表消息的长度,然后发送消息。
  3. 用前哨字节分隔消息。

然后,调用recv并累积结果,直到缓冲区中有完整的消息为止。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM