多线程Python套接字发送器/客户端

时间:2014-10-16 16:18:27

标签: python multithreading sockets twisted

我有一个Twisted应用程序,它正在侦听Int32StringReceiver消息,然后将它们重新发送到另一个应用程序。基本上,它是一个路由器,但它有一些智能,反省数据的去向。

我的问题在于出站方面,收到大量错误消息等等。

Inbound是一个类Receiver(Int32StringReceiver):

def doActualForwarding(self, data):         
    self.stats.recvBits  += 8 * (4 + len(data))
    self.stats.recvMsgs += 1
    dlen = len(data) 
    if dlen > 1024*256:
        self.logger.info("router.Receiver.doActualForwarding(): data len: %s" % (dlen))
    self.router.forward(data)

def stringReceived(self, data):
    d = threads.deferToThread(self.doActualForwarding, data)
    d.addCallback(self.forwardingDoneOkay)
    d.addErrback(self.forwardingDoneError)

self.router是实例化的对象,需要通过套接字通信以相同的格式发送这些消息。所以,它只是转过来并在Router类中执行此操作:

def connect(self):
    if self.sock:
        try:
            self.sock.close()
        except:
            pass
    try:
        self.stats.connectAttempts += 1
        self.sock = socket.socket()
        self.sock.settimeout(self.CONNECT_TIMEOUT)
        self.sock.connect(self.destination)
        self.sock.settimeout(self.SEND_TIMEOUT)
        self.set_keepalive_linux(self.sock)
        self.connected = True
        self.log.info("connected to %s" % (self.destination,))
        self.stats.reconnects += 1
        self.stats.connectCompletes += 1
        return True
    except Exception, e:
        self.connected = False
        if not self.drop_ok:
            self.log.error("connect %s: %s" % (self.destination, e))
        return False

def send(self, msg):
    trynum = 0
    while trynum < self.MAX_SEND_ATTEMPTS:
        self.logSent()
        if not self.connected:
            if not self.connect():
                self.stats.badSends += 1
                time.sleep(self.DELAY_BEFORE_RECONNECT)
                continue
        try:
            if ((time.time() - self.lastReconnectTime) > self.RECONNECT_EVERY):
                self.lastReconnectTime = time.time()
                assert False, "Reconnecting with destination to redistribute load."
            self.sock.sendall(msg)
            #self.closeSocket()
            self.stats.events += 1
            return True
        except Exception, e:
            whichKind = None
            if 'Broken pipe' in str(e):
                self.stats.brokenPipe += 1
            elif 'Resource temporarily unavilable' in str(e):
                self.stats.resourceTempUnavail += 1
            elif 'Bad file descriptor' in str(e):
                self.stats.badFileDescriptor += 1
            self.log.error("send: %s %s" % (str(self.destination), str(e)))
            try:
                self.sock.close()
            except:
                pass
            self.connected = False
            self.stats.badSends += 1
        trynum += 1
        if trynum == 1:
            self.stats.eventsWithRetry += 1
    if trynum > 1:
        self.log.warning("recon_sender.send(): Trynum non-singular, was: %s" % (trynum))
    return False

def __del__(self):
    try:
        self.sock.close()
    except:
        pass

问题:

  1. Python的Socket库线程是否安全?也就是说,在功能上,两个或多个线程具有指向对象Router的指针。两个线程都在调用self.sock.sendall(msg),我担心他们会相互踩踏。

  2. 一个症状是连续的消息可能会相互附加。我对此并不确定,但看起来就是这样。

  3. 我看到很多资源温度。 unavail(意思是目的地忙),大约相同数量的破损管道和少量坏文件描述符。

    • [Errno 9]错误的文件描述符
    • [Errno 11]资源暂时无法使用
    • [Errno 32]破管
  4. 这些消息对应于通过此事件的消息数量的0.5%(.005)。

    1. 我试图让每个发送一个connect / sendall / shutdown / close,但这导致大量关于&#39;连接重置的消息。
    2. 每个人似乎都倾向于处理在套接字上处理多线程接收的代码,但对套接字上的多线程SENDING没有太多评论。

      1. 我也试图使用(可能不正确):

        导入线程     self.lock = threading.Lock()     与self.lock:         sock.sendall(MSG)

      2. 但是这导致了关于超时(yuck)的错误消息。

        1. 有人能指出一些很好的例子(或提供一些?!?!?!?)来展示多线程套接字sendall()?

1 个答案:

答案 0 :(得分:0)

我想说如果进程不需要彼此通信,那么最好的解决方案是生成一个新进程来处理每个传入连接。这样您就不必担心锁定,因为每个连接都将单独处理。

简单的实施将是:

import socket
import multiprocessing
import pdb
import random
from pycurl import Curl
import os
import time
import re

class query(object):
    pid, addr, conn, url, ua, ref = [None for i in range(6)]
    compression = True

    def __init__(self, conn, addr):
        self.pid = addr[1]
        self.addr = addr
        self.conn = conn
        self.process()

    def process(self):
        #do your socket stuff here

class ProxyServer(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def start(self):
        logging.info("Server started on %s:%i" % (self.host, self.port))
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind((self.host, self.port))
        self.sock.listen(0)

        while True:
            conn, addr = self.sock.accept()
            logging.info('Connection made from %s' % conn)
            proc = multiprocessing.Process(target=query, args=(conn, addr))
            proc.daemon = True
            proc.start()
            logging.info('Started processing query %r for %s' % (proc, addr))

if __name__ == "__main__":
    serv = ProxyServer(host, port)
    try:
        serv.start()
    except:
    finally:
        for proc in multiprocessing.active_children():
            proc.terminate()
            proc.join()

请记住,这是我从旧的概念验证代码中删除的一个示例,您必须在它准备好生产之前稍微调整一下。