使用套接字接收和传输数据

时间:2018-02-13 00:10:57

标签: python multithreading sockets

我在使用Python套接字接收和发送数据方面遇到了麻烦。在我的脚本中,我需要监听套接字中的传入数据并读取FIFO文件以获得响应,并在找到\ n时使用套接字发送它。我创建了单独的线程来读取FIFO并且它可以工作,但有时它真的很慢。是否可以在主线程中执行这两项操作?我的代码:

#!/usr/bin/python

from __future__ import absolute_import, print_function, unicode_literals

from optparse import OptionParser, make_option
import os
import errno
import sys
import socket
import uuid
import dbus
import dbus.service
import dbus.mainloop.glib
import time

from threading import Thread
try:
  from gi.repository import GObject
except ImportError:
  import gobject as GObject

class ArduinoFifo:
    fifofile = -1
    OUT_PIPE_FILE = '/tmp/ble_pipe_out'

    def removeFile(self, filename):
        try:
            os.remove(filename)
        except OSError as e: # this would be "except OSError, e:" before Python 2.6
            if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory
                print(e)
                raise # re-raise exception if a different error occured

    def createFifo(self):
        print('removing pipe file\n')
        self.removeFile(self.OUT_PIPE_FILE)

        print('making pipe\n')
        try:
            os.mkfifo(self.OUT_PIPE_FILE, 0777)
        except OSError as err:
            print (err)
            raise

    def openFifo(self):
        print('waiting to open pipe\n')
        try:
            self.fifofile = os.open(self.OUT_PIPE_FILE, os.O_WRONLY) # | os.O_NONBLOCK)
        except OSError as err:
            print (err)

    def writeFifo(self, data):
        try:
            if (self.fifofile == -1):
                openFifo(self)
            os.write(self.fifofile, data)
        except OSError as err:
            print (err)

class FIFOReader(Thread):
    def __init__(self, server_sock):
        super(FIFOReader, self).__init__()
        self.server_sock = server_sock
        self.daemon = True
        self.received_msg = ""
        self.cancelled = False
        print('remove in fifo')
        try:
            os.remove("/tmp/ble_pipe_in")
        except OSError as e: # this would be "except OSError, e:" before Python 2.6
                if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory
                        print(e)
                raise

        print('create in fifo')
        try:
            os.mkfifo("/tmp/ble_pipe_in", 0777)
        except OSError as err:
                print (err)
            raise

        print('open in fifo')
        try:
            self.fifofile = os.open("/tmp/ble_pipe_in", os.O_RDWR)
        except OSError as err:
                print (err)
        print('fifo in opened')

    def run(self):
        while not self.cancelled:
            print("READING")
            self.received_msg += os.read(self.fifofile, 1)
            print("read: %s\n" % self.received_msg)
            if "\n" in self.received_msg :
                print("Sending Message...")
                self.server_sock.send(self.received_msg)
                self.received_msg = ""

    def cancel(self):
        self.cancelled = True

myfifo = ArduinoFifo()

class Profile(dbus.service.Object):
    fd = -1

    @dbus.service.method("org.bluez.Profile1",
                    in_signature="", out_signature="")
    def Release(self):
        print("Release")
        mainloop.quit()

    @dbus.service.method("org.bluez.Profile1",
                    in_signature="", out_signature="")
    def Cancel(self):
        print("Cancel")


    @dbus.service.method("org.bluez.Profile1",
                in_signature="oha{sv}", out_signature="")
    def NewConnection(self, path, fd, properties):
        global received_msg
        self.fd = fd.take()
        print("NewConnection(%s, %d)" % (path, self.fd))


        server_sock = socket.fromfd(self.fd, socket.AF_UNIX, socket.SOCK_STREAM)
        server_sock.setblocking(1)

        myfifo.openFifo()
        infifo = FIFOReader(server_sock)
        infifo.start()

        print('enter recv loop\n')
        try:
            while True:
                data = server_sock.recv(1024)
                #print("received: %s" % data)
            if data:
                    myfifo.writeFifo(data)
            #if data == "h":
                #server_sock.send("Hello!\n")
        except IOError as err:
            print (err)
            pass

        server_sock.close()
        print("all done")
        os.kill(os.getpid(), 9)



    @dbus.service.method("org.bluez.Profile1",
                in_signature="o", out_signature="")
    def RequestDisconnection(self, path):
        print("RequestDisconnection(%s)" % (path))

        if (self.fd > 0):
            os.close(self.fd)
            self.fd = -1

if __name__ == '__main__':
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    bus = dbus.SystemBus()

    manager = dbus.Interface(bus.get_object("org.bluez",
                "/org/bluez"), "org.bluez.ProfileManager1")

    option_list = [
            make_option("-C", "--channel", action="store",
                    type="int", dest="channel",
                    default=None),
            ]

    parser = OptionParser(option_list=option_list)

    (options, args) = parser.parse_args()

    options.uuid = "1101"
    options.psm = "3"
    options.role = "server"
    options.name = "Edison SPP Loopback"
    options.service = "spp char loopback"
    options.path = "/foo/bar/profile"
    options.auto_connect = False
    options.record = ""

    profile = Profile(bus, options.path)

    mainloop = GObject.MainLoop()

    opts = {
            "AutoConnect" : options.auto_connect,
        }

    if (options.name):
        opts["Name"] = options.name

    if (options.role):
        opts["Role"] = options.role

    if (options.psm is not None):
        opts["PSM"] = dbus.UInt16(options.psm)

    if (options.channel is not None):
        opts["Channel"] = dbus.UInt16(options.channel)

    if (options.record):
        opts["ServiceRecord"] = options.record

    if (options.service):
        opts["Service"] = options.service

    if not options.uuid:
        options.uuid = str(uuid.uuid4())

    manager.RegisterProfile(options.path, options.uuid, opts)

    myfifo.createFifo()

    mainloop.run()
编辑:我认为问题在于将数据写入FIFO或从套接字接收传入数据,因为在我的代码中,当我想使用fgets函数从输入FIFO读取数据时,我有这种延迟。

EIDT2:我用它来立即接收消息并一个接一个地发送响应

1 个答案:

答案 0 :(得分:0)

我怀疑这个问题与单独的线程有关。 Python中的“线程”不一定是操作系统级线程,但可能只是异步操作主操作系统级线程进程。 In cPython, which most people use, this is how they work.但我确实看到了几个可能的问题:

我不熟悉其中一些库,但os.read(self.fifofile, 1)脱颖而出。如果你使用内置open()(不是os中的那个)或BufferedReader,那么这将被缓冲,因此可以。但是os.open是一个低级调用,不会缓冲读取或写入,所以你实际上是从文件句柄一次读取1个字节,这不是一个好主意,因为它可能导致因各种难以追查的原因而放缓。您应该为此使用更高级别的库,或者自己进行缓冲。

其次,如果您的Python解释器每次都在内部创建一个新字符串,那么您对消息字符串的读取输入的+=重复将会很慢。所以你可能会看到O(N ^ 2),其中N是消息大小时间复杂度,应该是O(N)。这取决于你的翻译,所以为了便于携带,你应该改为列表。

不相关,但如果您不知道您的FIFO文件是否为文本,则不应在文本模式下打开它,否则您将遇到错误。字符串只允许有效的文本字节,UTF-8(如果它是Py3)和我认为ASCII(如果它是Py2),如果收到,则会收到错误,比如0x00

希望这有帮助。