2014-12-13 2 views
1

У меня есть сокет, который прослушивает входящие соединения, и я могу закрыть соединение с помощью кнопки, когда она была установлена, и данные перемещаются, но возможно ли использовать кнопку для остановки сокета еще до установления соединения и начала цикла while?Как закрыть сокет, который прослушивает, но еще не принял соединения

Вот код для сокета:

def serverstart(self): 
      self.buttonswitch("1") 
      host = self.intip 
      port = 5000 
      s= socket.socket(socket.AF_INET6) 
      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
      s.bind((host, port)) 

      s.listen(1) 
      c, addr = s.accept() 
      print "Connection from: " + str(addr) 
      self.serverstatus = "1" 
      status = self.serverstatus 
      while status == "1": 
       data = c.recv(1500) 
       print len(data) 
       if not data: 
         break 
       data = str(data).upper() 
       c.send(data) 
       status = self.serverstatus 
      c.close() 
      s.close() 
      print "Closing socket" 
      self.buttonswitch("0") 

Я использую функцию buttonswitch для включения и отключения запуска и остановки кнопки в тандеме с состоянием сервера

EDIT: Я избавилась переменной self.serverstatus и добавил это вместо (создать подключение к сокету только, чтобы закрыть его):

def serverstop(self, status): 
      s = socket.socket(socket.AF_INET6) 
      self.s.close() 
      try: 
       self.c.close() 
      except: 
       s.connect((self.host,self.port)) 
       s.close() 
      self.buttonswitch("0") 

Единственным недостатком является то, что, когда я с из-за соединения он вызывает ошибку о сломанной трубе. Однако это не влияет на функциональность.

Если у вас есть какие-либо идеи, чтобы быть верным, я был бы рад узнать, спасибо.

EDIT2: Я выложу весь код участвует в качестве ссылки:

from Tkinter import * 
import socket, threading, time 
import netifaces as ni 

class Application(Frame): 


     def __init__(self, master): 
      """ Initialize the Frame""" 
      Frame.__init__(self,master) 
      self.grid() 
      self.create_widgets() 

     def create_widgets(self): 
      self.label1 = Label(text = "Target IPv6 address") 
      self.label1.grid(row=1, column=0) 

      self.entry1 = Entry(bd = 5) 
      self.entry1.grid(row=1, column = 1, columnspan = 2) 

      self.button1 = Button(text = "Start", command = lambda: self.threadcontrol("2")) 
      self.button1.grid(row=1, column = 3) 

      self.button2 = Button(text = "Start", command = lambda: self.threadcontrol("1"), state = DISABLED) 
      self.button2.grid(row=2, column=3) 

      self.button3 = Button(text = "Stop", command = lambda: self.serverstop("0"), state = DISABLED) 
      self.button3.grid(row=2, column=4) 

      self.button4 = Button(text = "Stop", command = lambda: self.clientstop("0"), state = DISABLED) 
      self.button4.grid(row=1, column=4) 

      self.label2 = Label(text = "Choose interface to listen") 
      self.label2.grid(row=2, column=0) 

      self.interfaces = Menubutton(text="------", relief=RAISED) 
      self.interfaces.grid(row=2, column=1, sticky="w") 
      self.interfaces.menu = Menu(self.interfaces, tearoff=0) 
      self.interfaces["menu"] = self.interfaces.menu 
      self.menubox() 

      self.label3 = Label(text = "") 
      self.label3.grid(row=2, column=2, sticky="w") 

     def menubox(self): 
      self.interfaces.menu.add_command(label="------", command = lambda interface="------": self.callback(interface)) 
      for interface in ni.interfaces(): 
       if interface.startswith('eth'): 
        self.interfaces.menu.add_command(label=interface, command = lambda interface=interface: self.callback(interface)) 
       else: 
        pass 

     def callback(self, interface): 
      if interface.startswith('eth'): 
       self.intip = ni.ifaddresses(interface)[ni.AF_INET6][0]['addr'] 
       self.interfaces["text"] = interface 
       if self.intip.startswith('fe80'): 
        self.label3["text"] = "No IPv6 address found" 
        self.button2["state"] = DISABLED 
       else: 
        self.label3["text"] = self.intip 
        self.button2["state"] = 'normal' 
      else: 
       self.interfaces["text"] = "------" 
       self.label3["text"] = "" 
       self.button2["state"] = DISABLED 

     def buttonswitch(self, flip): 
      if flip == "1": 
       # Disables server start button and enables server stop button. 
       self.button2["state"] = DISABLED 
       self.button3["state"] = "normal" 
      elif flip == "0": 
       # Disables server stop button and enables server start button 
       self.button3["state"] = DISABLED 
       self.button2["state"] = 'normal' 
      elif flip == "2": 
       # Enables client stop button 
       self.button4["state"] = 'normal' 
      elif flip == "3": 
       # Disables client stop button 
       self.button4["state"] = DISABLED 

     def threadcontrol(self, threadtype): 
      if threadtype == "1": 
       self.thread1 = threading.Thread(target = self.serverstart) 
       self.thread1.start() 
      elif threadtype == "2": 
       self.thread2 = threading.Thread(target = self.clientstart) 
       self.thread2.start() 
      else: 
       pass 

     def clientstop(self, status): 
      self.clientstatus = "1" 
      if status =="0": 
       self.clientstatus = status 

     def serverstop(self, status): 
      self.s.close() 

     def serverstart(self): 
      self.buttonswitch("1") 
      self.host = self.intip 
      self.port = 5000 
      self.s = socket.socket(socket.AF_INET6) 
      self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
      self.s.bind((self.host, self.port)) 

      self.s.listen(1) 
      self.c, addr = self.s.accept() 
      print "Connection from: " + str(addr) 
      while True: 
       data = self.c.recv(1500) 
       print len(data) 
       if not data: 
         break 
       data = str(data).upper() 
       self.c.send(data) 
      self.c.close() 
      self.s.close() 
      print "Closing socket" 
      self.buttonswitch("0") 

     def clientstart(self): 
      targetip = self.entry1.get() 
      host = targetip 
      port = 5000 

      s = socket.socket(socket.AF_INET6) 
      s.connect((host,port)) 

      self.buttonswitch("2") 
      openfile = open('paskadata') 
      message = openfile.read() 
      self.clientstatus = "1" 
      status = self.clientstatus 
      n = 1 
      while status == "1": 
       s.send(message) 
       data = s.recv(1500) 
       status = self.clientstatus 
       print n 
       n = n + 1 
       time.sleep(50.0/1000) 
      s.close() 
      self.buttonswitch("3") 

root = Tk() 

root.title("IPv6 traffic generator") 
root.geometry("450x200") 

app = Application(root) 
root.mainloop() 
+0

Я не понимаю, как вы ожидаете, что это сработает. Даже если графический интерфейс работает в другом потоке с сервера, поэтому он может модифицировать 'self.serverstatus', пока сервер занят обработкой сообщений, которые все равно не будут иметь никакого эффекта, если вы заблокированы на' recv' или 'send'. – abarnert

+0

В любом случае, если вы просто используете переменные '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''), который, я уверен, гарантированно прервет любые блокировки 'accept',' recv', 'send' в этом сокете и заставит его поднять либо« EBADFD »,« ECONNRESET », либо« EINTR ». – abarnert

+0

Я попытался изменить переменные на self.s и self.c соответственно, но пока я смог закрыть соединение после его запуска с помощью self.c.close(), используя self.s.close() didn ' t отключите розетку от прослушивания соединений. – Nyoa

ответ

0

Вопрос заключается в том, что accept является блокировка вызова по умолчанию. Фактически вы не вернетесь с accept, если в очереди нет ожидающего подключения.

Вы можете использовать асинхронную библиотеку, например gevent, и развернуть отдельную зеленую роту, в которой вы обрабатываете события пользовательского интерфейса.

В качестве альтернативы вы можете установить, что сокет не блокируется напрямую, используя метод setblocking на сокете. Это потребует от вас «повторить» любые потенциально блокирующие вызовы сокетов с использованием метода типа опроса.

Другим подобным подходом было бы использовать метод settimeout, который приведет к таймауту блокировки, если какой-либо из них займет слишком много времени. Вы можете установить тайм-аут на что-то разумное, например, 50 миллисекунд, чтобы человек не беспокоился и периодически обрабатывал события пользовательского интерфейса. Опять же, вам нужно будет повторить вызовы блокирующего сокета при возникновении тайм-аутов.

Лично я предпочитаю подход к зелене, потому что он намного проще.

+0

Но так «recv» (и 'send'), поэтому, если нет данных для получения, его кнопка тоже не будет работать. – abarnert

+0

Правда, но мой ответ предполагает, что все операции сокета не блокируются так или иначе. – b4hand

+0

В то время я этого не писал. Но я хочу сказать, что нам нужно знать, как/почему его кнопка уже работает, прежде чем мы сможем объяснить, можно ли заставить ее работать и на 'accept', или же он должен полностью изменить свой дизайн. – abarnert

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