2016-04-29 63 views
2

从我的理解蟒蛇只能同时运行1个线程,这样如果我做这样的事情Python的 - 多线程插座

import socket, select 
from threading import Thread 
import config 

class Source(Thread): 
    def __init__(self): 
     self._wait = False 
     self._host = (config.HOST, config.PORT + 1) 
     self._socket = socket.socket() 
     self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     self._sock = None 
     self._connections = [] 
     self._mount = "None" 
     self._writers = [] 
     self._createServer() 
     Thread.__init__(self) 

    def _createServer(self): 
     self._socket.bind(self._host) 
     self._socket.listen(2) 
     self._connections.append(self._socket) 
     self._audioPackets=[] 

    def _addPacket(self, packet): 
     self._audioPackets.append(packet) 

    def _removePacket(self, packet): 
     self._audioPackets.remove(packet) 

    def _getPacket(self): 
     if len(self._audioPackets) > 0: 
      return self._audioPackets[0] 
     else: 
      return None 

    def _sendOK(self, sock): 
     sock.send("OK") 

    def _sendDenied(self, sock): 
     sock.send("DENIED") 

    def _sendMount(self, sock): 
     sock.send("mount:{0}".format(self._mount)) 

    def _sendBufPacket(self, sock, packet): 
     packet = "buffer:%s" % packet 
     sock.send(packet) 

    def recv(self, sock, data): 
     data = data.split(":", 1) 
     if data[0] == "WAIT": self._wait = True 
     elif data[0] == "STOP_WAITING": self._wait = False 
     elif data[0] == "LOGIN": 
      if data[1] == config.SOURCE_AUTH: 
       self._source = sock 
       self._sendOK(sock) 
      else: 
       self._sendClose(sock) 
     elif data[0] == "MOUNT": 
      if self._source == sock: 
       self._mount = data[1] 
      else: 
       self._sendClose(sock) 

     elif data[0] == "CLIENT": 
      self._sendMount(sock) 
      self._writers.append(sock) 


    def _sendCloseAll(self): 
     for sock in self._connections: 
      sock.send("CLOSE") 
      sock.close() 

    def _sendClose(self, sock): 
     sock.send("CLOSE") 
     sock.close() 

    def main(self): 
     while True: 
      rl, wl, xl = select.select(self._connections, self._writers, [], 0.2) 
      for sock in rl: 
       if sock == self._socket: 
        con, ip = sock.accept() 
        self._connections.append(con) 
       else: 
        data = sock.recv(config.BUFFER) 
        if data: 
         self.recv(sock, data) 
        else: 
         if sock in self._writers: 
          self._writers.remove(sock) 
         if sock in self._connections: 
          self._connections.remove(sock) 
      for sock in wl: 
       packet = self._getPacket() 
       if packet != None: 
        self._sendBufPacket(sock, packet) 

    def run(self): 
     self.main() 

class writeThread(Thread): 
     def __init__(self): 
      self.running = False 

     def make(self, client): 
      self.client = client 
      self.running = True 

     def run(self): 
      host = (config.HOST, config.PORT+1) 
      sock = socket.socket() 
      sock.connect(host) 
      sock.send("CLIENT") 
      sock.send("MOUNT:mountpoint") 
      while self.running: 
       data = sock.recv(config.BUFFER) 
       if data: 
        data = data.split(":", 1) 
        if data[0] == "buffer": 
        self.client.send(data[1]) 
        elif data[0] == "CLOSE": 
         self.client.close() 
         break 


if __name__=="__main__": 
    source = Source() 
    source.start() 
    webserver = WebServer() 
    webserver.runloop() 

,如果我需要建立web服务器部分我会的。但是,我会解释它。 好吧,所以基本上当有人连接到已设置的挂载点下的websever时,他们将获得自己的个人线程,然后从Source()获取数据并将其发送给他们。现在说另一个人连接到挂载点,最后一个客户端以及源代码仍在继续。考虑到有两个活动线程,新客户端不会阻止获取源数据吗?

回答

2

根据您所问的问题,您了解线程如何在Python中工作似乎不正确。如果使用正确,线程将不会被阻塞:您可以使用Python实例化多个线程。限制在于,由于Global Interpreter Lock(GIL),您无法获得线程编程中预期的完全并行性(例如,同时执行并因此减少了运行时)。 你的情况将发生什么情况是,两个线程将一起采用相同的时间量,如果它们按顺序执行(尽管这不一定是实际发生的情况)。

0

好吧,我有复制并粘贴,我已经为我目前工作的一个项目写了一些Python3代码。通过修改,您可以使此代码服务于您的目的。

该代码使用多处理和多线程。出于我的目的,我正在使用多处理功能,因此套接字将在一个处理器上运行,并且我可以在另一个处理器上运行GUI程序。如果您愿意,可以删除多处理器部件。下面的代码运行套接字消息服务器。服务器将一次侦听一个客户端。客户端连接后,将启动一个新线程来处理服务器和每个客户端之间的所有通信。服务器将继续搜索客户端。然而,目前服务器只侦听每个客户端发送的数据,然后将其打印到终端。通过少量的努力,您可以修改我的代码,从服务器向每个客户端单独发送信息。

import multiprocessing 
import threading 
from threading import Thread 

class ThreadedServer(object): 

    def __init__(self, host, port): 
    self.host = host 
    self.port = port 
    self.sock = socket(AF_INET, SOCK_STREAM) 
    self.sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 
    self.sock.bind((self.host, self.port)) 

    def listen(self):  
     self.sock.listen(3) #Allow 3 Clients to connect to this server 
     while True: 
      #The program will search for one client at a time 
      print("Searching for Client") 
      client, address = self.sock.accept() 
      print(address, " is connected") 
      #client.settimeout(60) 

      #Once a client has been found, start a individual client thread 
      d = threading.Thread(target = self.listenToClient, args=(client, address)) 
      d.daemon = True 
      d.start() 

def listenToClient(self, client, address): 
    size = 1024 
    while True: 
     try: 
      data = client.recv(size) 
      if not data: 
       break 
      if data: 
       print(data) 
       #client.send(response) 
      else: 
       raise error('Client disconnected') 
     except: 
      client.close() 
      return False 

def dataSharingHost(): 
    #Using Sockets to send information between Processes 
    #This is the server Function 
    #ThreadServer(Host_IP, Port_Number), for LocalHost use '' 
    ThreadedServer('', 8000).listen() 

def Main(): 
    commServer = multiprocessing.Process(target=dataSharingHost, args=()) 
    commServer.daemon = True 
    commServer.start() 

if __name__== '__main__': 
    Main() 

为了公平起见,我的代码从https://www.youtube.com/watch?v=qELZAi4yra8进行了修改。这些视频涵盖了客户端代码。我认为第三个视频涵盖了多个客户端连接。

+0

'客户端,地址= self.sock.accept()'如果另一个客户端连接或客户端重新连接,这不会引发错误吗? –

+0

我一次连接3个客户端时一直没有问题。 self.sock.listen(3)将服务器配置为一次接受3个客户端。事实证明,“地址”变量实际上包含两条信息。第一部分是客户端的IP地址,如果你运行这个代码,它应该是127.0.0.1。第二条信息是“地址”变量是每个连接客户端的唯一ID。因此每个客户都会得到它自己的ID。目前,这些代码还不够复杂,无法让客户重新连接。那必须是我在稍后的交叉路口才能解决的问题。 – jberry