2016-04-29 4 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() 

, если мне нужно, чтобы построить веб-сервер части я. Но я объясню это. Итак, в основном, когда кто-то подключается к веб-серверу под установленной точкой монтирования, у них будет собственный личный поток, который затем захватывает данные от Source() и отправляет их им. Теперь скажите, что другой человек подключается к точке монтирования, а последний клиент, а также источник все еще идет. Разве новый клиент не будет заблокирован от получения исходных данных, учитывая наличие двух активных потоков?

ответ

2

Ваше понимание того, как Threads работают на 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. Клиентский код распространяется на эти видео. Я думаю, что 3-е видео охватывает несколько клиентских подключений.

+0

'client, address = self.sock.accept()' не приведет ли это к ошибке при подключении другого клиента или при повторном подключении клиента? –

+0

У меня не было проблемы с подключением 3 клиентов одновременно. self.sock.listen (3) настраивает сервер для одновременного приема 3 клиентов. Оказывается, переменная «адрес» фактически содержит две части информации. Первая часть - это IP-адрес клиента, который должен быть 127.0.0.1, если вы запустите этот код. Вторая часть информации - это «адресная» переменная - это уникальный идентификатор для каждого подключенного клиента. Поэтому каждый клиент получит свой собственный идентификатор. В настоящее время этот код недостаточно сложный, чтобы клиенты могли повторно подключаться. Это должно быть чем-то, что я выдумываю на более позднем стыке. – jberry

Смежные вопросы