Python 如何关闭正在侦听但尚未接受连接的套接字
我有一个监听传入连接的套接字,一旦连接建立且数据移动,我就可以使用按钮关闭连接,但我是否可以在连接建立和while循环开始之前使用按钮停止套接字 以下是套接字的代码:Python 如何关闭正在侦听但尚未接受连接的套接字,python,sockets,user-interface,Python,Sockets,User Interface,我有一个监听传入连接的套接字,一旦连接建立且数据移动,我就可以使用按钮关闭连接,但我是否可以在连接建立和while循环开始之前使用按钮停止套接字 以下是套接字的代码: def serverstart(self): self.buttonswitch("1") host = self.intip port = 5000 s= socket.socket(socket.AF_INET6) s.sets
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功能,根据服务器的状态启用和禁用停止和启动按钮
编辑:我去掉了self.serverstatus变量并添加了这个变量(创建到套接字的连接以关闭它):
唯一的缺点是,当我关闭一个连接时,它会引发一个关于管道破裂的错误。但这并不影响功能
如果你对此有任何更正确的想法,我很乐意学习,谢谢
编辑2:我将发布所有相关代码以供参考:
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()
问题在于默认情况下,
accept
是一个阻塞调用。除非队列上已经存在挂起的连接,否则您实际上不会从accept
返回
您可以使用一个异步库,例如,启动一个单独的greenlet,在其中处理用户界面事件
或者,您可以使用套接字上的方法直接将套接字设置为非阻塞。这将要求您使用轮询类型方法“重试”任何可能阻塞的套接字调用
另一种类似的方法是使用这种方法,如果阻塞操作中的任何一个花费的时间太长,就会导致阻塞操作超时。您可以将超时时间设置为合理的值,比如50毫秒,这样人类就不会被打扰,并定期处理UI事件。同样,当超时发生时,您需要重试阻塞套接字调用
就个人而言,我更喜欢greenlet方法,因为它简单得多。但是
recv
(和send
)也是如此,所以如果没有数据接收,他的按钮也不会在那里工作。是的,但我的答案是让所有套接字操作都以这种或那种方式不阻塞。在我写这篇文章的时候没有。但我的观点是,我们需要知道他的按钮是如何/为什么工作的,然后才能解释是否有可能使其在accept
上工作,或者他是否必须完全更改其设计。我的按钮将self.serverstatus状态更改为0,这足以停止while循环。我正在制作一个适用于IPv6的数据包生成器,因此一旦连接启动,循环就会在一秒钟内迭代数千次。唯一的问题是,在客户端连接到套接字之前,我需要其他方法来关闭它。对于您的最后一次编辑,使用settimeout
并像那样重试通常比仅使用select
(或者,如果您使用的是3.4+,则使用选择器
模块,这稍微简单一些)更复杂和复杂1.我不明白你怎么会期望这样。即使GUI在与服务器不同的线程中运行,因此它可以在服务器忙于处理消息时修改self.serverstatus,但如果您在recv
或send
上被阻止,这仍然不会产生任何影响。无论如何,如果您只需要创建s
和c
成员变量,您总是可以调用self.s.close()
和self.c.close()
(首先检查它们是否存在,如果合适的话),我很确定这会中断该套接字上的任何阻塞accept
,recv
,send
,并使其引发EBADFD
,ECONNRESET
,或EINTR
。我试图分别将变量更改为self.s和self.c,但虽然我能够在连接启动后使用self.c.close()关闭连接,但使用self.s.close()并没有阻止套接字侦听连接。在编辑的版本中,您仍然使用局部变量s
,非self.s
。另外,我刚才向您解释了self.c.close()
将使阻塞的recv
引发ECONNRESET
或类似错误,因此我不确定您为什么对它引发错误感到惊讶。更重要的是,您仍然必须向我们解释如何并行运行GUI和服务器。您是否为每个线程使用单独的线程?或者类似于gevent
?还是怎样因为你必须要做点什么。
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()