Python3套接字,套接字上的随机部分结果

时间:2017-12-11 17:16:39

标签: python sockets

我使用Python套接字编写了一个基本的客户端/服务器接口(仅引用相关的代码部分,完整脚本:(SERVER: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

2 个答案:

答案 0 :(得分:0)

方法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

答案 1 :(得分:0)

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

  1. 发送固定长度的消息。
  2. 发送一个固定数量的字节,表示消息的长度,然后是消息。
  3. 使用sentinel字节分隔消息。
  4. 然后,调用recv并累积结果,直到缓冲区中有完整的消息。