2016-04-29 62 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