ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – CTRL-C在Python中的表现不同

2019-08-27 07:56:26  阅读:73  来源: 互联网

标签:java python 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();
        }
    }

}

和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)

在上面的两段代码片段中,我创建了一个简单的服务器,它监听给定端口上的TCP请求.在Java代码的情况下按下Ctrl C时,JVM退出,而在Python代码的情况下,我得到的只是shell的^ C.我可以停止服务器的唯一方法是按Ctrl Z然后手动终止进程.

所以我提出了一个计划;为什么没有一个侦听Ctrl Z并退出应用程序的sighandler?很酷,所以我想出来:

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)

但现在,似乎我的情况更糟!现在按下shell上的Ctrl C会发出’^ C’并按下shell上的Ctrl Z会发出’^ Z’.

所以我的问题是,为什么这种奇怪的行为呢?我可能有多个服务器进程在同一进程中作为单独的线程运行,所以在进程收到SIGINT时杀死服务器的任何干净方法? BTW在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"

标签:java,python,sockets
来源: https://codeday.me/bug/20190827/1738677.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有