sas*_*uke 3 python java sockets
我最近开始学习Python(这里是长期的Java程序员),目前正在编写一些简单的服务器程序。问题是,对于看似相似的一段代码,Java对应部分正确响应SIGINT信号(Ctrl+ C),而Python则没有响应。当使用单独的线程生成服务器时,可以看到这一点。代码如下:
// Java code
package pkg;
import java.io.*;
import java.net.*;
public class ServerTest {
public static void main(final String[] args) throws Exception {
final Thread t = new Server();
t.start();
}
}
class Server extends Thread {
@Override
public void run() {
try {
final ServerSocket sock = new ServerSocket(12345);
while(true) {
final Socket clientSock = sock.accept();
clientSock.close();
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
和Python代码:
# Python code
import threading, sys, socket, signal
def startserver():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 12345))
s.listen(1)
while True:
csock, caddr = s.accept()
csock.sendall('Get off my lawn kids...\n')
csock.close()
if __name__ == '__main__':
try:
t = threading.Thread(target=startserver)
t.start()
except:
sys.exit(1)
Run Code Online (Sandbox Code Playgroud)
在以上两个代码片段中,我都创建了一个简单的服务器,该服务器在给定端口上侦听TCP请求。对于Java代码,如果按Ctrl+ C,则JVM退出,而对于Python代码,我得到的只是^C在shell上。我可以停止服务器的唯一方法是按Ctrl+ Z,然后手动终止该进程。
所以我想出了一个计划。为什么没有Sighandler监听Ctrl+ Z并退出应用程序?很酷,所以我想出了:
import threading, sys, socket, signal
def startserver():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 12345))
s.listen(1)
while True:
csock, caddr = s.accept()
csock.sendall('Get off my lawn kids...\n')
csock.close()
def ctrlz_handler(*args, **kwargs):
sys.exit(1)
if __name__ == '__main__':
try:
signal.signal(signal.SIGTSTP, ctrlz_handler)
t = threading.Thread(target=startserver)
t.start()
except:
sys.exit(1)
Run Code Online (Sandbox Code Playgroud)
但是现在,看来我使情况变得更糟了!现在,在外壳上按Ctrl+ C会发出“ ^ C”,在外壳上按Ctrl+ Z会发出“ ^ Z”。
所以我的问题是,为什么这种奇怪的行为?我可能会在同一进程中将多个服务器进程作为单独的线程运行,因此,当进程收到消息时,有任何清除服务器的干净方法SIGINT吗?顺便说一句,在Ubuntu上使用Python 2.6.4。
TIA
佐助
几个问题:
不要捕获所有异常并静默退出。那是您可能做的最糟糕的事情。
除非您真的知道自己在做什么,否则不要抓住SIGTSTP。这不是要应用程序拦截的信号,如果您正在捕获它,则可能是您做错了什么。
KeyboardInterrupt仅发送到程序的初始线程,而不发送给其他线程。这样做有两个原因。通常,您想在一个地方处理^ C,而不是在碰巧接收到异常的随机任意线程中处理。而且,它有助于确保在正常操作中,大多数线程永远不会收到异步异常;这非常有用,因为(在包括Java在内的所有语言中)它们很难可靠地处理。
您永远不会在这里看到KeyboardInterrupt,因为您的主线程在启动辅助线程后立即退出。没有主线程可以接收该异常,因此将其丢弃。
修复方法有两个:保留主线程,因此KeyboardInterrupt有地方可去,并且仅捕获KeyboardInterrupt,而不是所有异常。
import threading, sys, socket, signal, time
def startserver():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 12345))
s.listen(1)
while True:
csock, caddr = s.accept()
csock.sendall('Get off my lawn kids...\n')
csock.close()
if __name__ == '__main__':
try:
t = threading.Thread(target=startserver)
t.start()
# Wait forever, so we can receive KeyboardInterrupt.
while True:
time.sleep(1)
except KeyboardInterrupt:
print "^C received"
sys.exit(1)
# We never get here.
raise RuntimeError, "not reached"
Run Code Online (Sandbox Code Playgroud)