检测控制台应用程序何时关闭/终止?

时间:2011-07-01 10:04:47

标签: c# mono console signals kill

我想为我的控制台应用程序安全退出,该应用程序将使用单声道在linux上运行,但我找不到一个解决方案来检测是否发送了一个信号,或者用户按下了ctrl + c。

在Windows上有内核函数SetConsoleCtrlHandler来完成这项工作,但这对单声道不起作用。

如何在我的控制台应用程序上获得关闭事件以安全退出?

2 个答案:

答案 0 :(得分:11)

你需要使用Mono.UnixSignal,Jonathan Pryor发布了一个很好的样本:http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html

在Mono页面上还有一个较短的示例:FAQ / Technical / Operating System Questions / Signal Handling

// Catch SIGINT and SIGUSR1
UnixSignal[] signals = new UnixSignal [] {
    new UnixSignal (Mono.Unix.Native.Signum.SIGINT),
    new UnixSignal (Mono.Unix.Native.Signum.SIGUSR1),
};

Thread signal_thread = new Thread (delegate () {
    while (true) {
        // Wait for a signal to be delivered
        int index = UnixSignal.WaitAny (signals, -1);

        Mono.Unix.Native.Signum signal = signals [index].Signum;

        // Notify the main thread that a signal was received,
        // you can use things like:
        //    Application.Invoke () for Gtk#
        //    Control.Invoke on Windows.Forms
        //    Write to a pipe created with UnixPipes for server apps.
        //    Use an AutoResetEvent

        // For example, this works with Gtk#    
        Application.Invoke (delegate () { ReceivedSignal (signal); });
    }});

答案 1 :(得分:10)

作为提供unix和windows实现的示例,请参见下文。请注意,使用Visual Studio时仍可以包含Mono.Posix dll。

我也添加了SIGTERM信号,因为当停止/重新启动你的app作为服务时,unix中的systemd会触发这个信号。

公开退出事件的界面

public class MainActivity extends Activity {

private ImageView image;
private Button uploadButton;
private Bitmap bitmap;
private Button selectImageButton;

// number of images to select
private static final int PICK_IMAGE = 1;

/**
 * called when the activity is first created
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // find the views
    image = (ImageView) findViewById(R.id.uploadImage);
    uploadButton = (Button) findViewById(R.id.uploadButton);

    // on click select an image
    selectImageButton = (Button) findViewById(R.id.selectImageButton);
    selectImageButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            selectImageFromGallery();

        }
    });

    // when uploadButton is clicked
    uploadButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            new ImageUploadTask().execute();
        }
    });
}

/**
 * Opens dialog picker, so the user can select image from the gallery. The
 * result is returned in the method <code>onActivityResult()</code>
 */
public void selectImageFromGallery() {
    Intent intent = new Intent();
    intent.setType("image/*");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(intent, "Select Picture"),
            PICK_IMAGE);
}

/**
 * Retrives the result returned from selecting image, by invoking the method
 * <code>selectImageFromGallery()</code>
 */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == PICK_IMAGE && resultCode == RESULT_OK
            && null != data) {

        Uri selectedImage = data.getData();
        String[] filePathColumn = { MediaStore.Images.Media.DATA };

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        Log.i("picturePath", "picturePath: " + picturePath);
        cursor.close();

        decodeFile(picturePath);

    }
}

/**
 * The method decodes the image file to avoid out of memory issues. Sets the
 * selected image in to the ImageView.
 * 
 * @param filePath
 */
public void decodeFile(String filePath) {
    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, o);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 1024;

    // Find the correct scale value. It should be the power of 2.
    int width_tmp = o.outWidth, height_tmp = o.outHeight;
    int scale = 1;
    while (true) {
        if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
            break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
    }

    // Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    bitmap = BitmapFactory.decodeFile(filePath, o2);

    image.setImageBitmap(bitmap);
}

/**
 * The class connects with server and uploads the photo
 * 
 * 
 */
class ImageUploadTask extends AsyncTask<Void, Void, String> {
    private String webAddressToPost = "URL";

    // private ProgressDialog dialog;
    private ProgressDialog dialog = new ProgressDialog(MainActivity.this);

    @Override
    protected void onPreExecute() {
        dialog.setMessage("Uploading...");
        dialog.show();
    }

    @Override
    protected String doInBackground(Void... params) {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(CompressFormat.JPEG, 100, bos);
        byte[] data = bos.toByteArray();
        String file = Base64.encodeToString(data, 0);

        ArrayList<NameValuePair> postData;
        postData = new ArrayList<NameValuePair>();

        JSONObject parentData = new JSONObject();
        JSONObject childData = new JSONObject();

        try {

            childData.put("fileContent", file);
            childData.put("fileName", "droid.jpeg");
            childData.put("fileType", "I");

            System.out.println(childData);

            parentData.put("mobile", childData);

            System.out.println(parentData);

            postData.add(new BasicNameValuePair("mobile", childData
                    .toString()));

            InputStream is = null;
            String jsonResponse = "";
            JSONObject jObj = null;

        } catch (JSONException e) {
            e.printStackTrace();
        }

        postData.add(new BasicNameValuePair("mobile", childData.toString()));

        InputStream is = null;
        String jsonResponse = "";
        JSONObject jObj = null;

        try {
            HttpClient httpClient = new DefaultHttpClient();
            HttpContext localContext = new BasicHttpContext();
            HttpPost httpPost = new HttpPost(webAddressToPost);

            /*
             * MultipartEntity entity = new MultipartEntity(
             * HttpMultipartMode.BROWSER_COMPATIBLE);
             * 
             * entity.addPart("uploaded", new StringBody(file));
             * 
             * entity.addPart("someOtherStringToSend", new StringBody(
             * "your string here"));
             */

            httpPost.setHeader("Content-Type",
                    "application/json; charset=utf-8");
            httpPost.setEntity(new StringEntity(parentData.toString()));

            // httpPost.setEntity(entity);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            System.out.println(httpResponse);

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(httpResponse.getEntity()
                            .getContent(), "UTF-8"));

            String sResponse = reader.readLine();
            Log.i("sResponse", "sResponse: " + sResponse);
            return sResponse;
        } catch (Exception e) {
            // something went wrong. connection with the server error
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        dialog.dismiss();
        Toast.makeText(getApplicationContext(), "file uploaded",
                Toast.LENGTH_LONG).show();
    }

}

Unix实现

public interface IExitSignal
{
    event EventHandler Exit;
}

Windows实施

public class UnixExitSignal : IExitSignal
{
    public event EventHandler Exit;

    UnixSignal[] signals = new UnixSignal[]{
        new UnixSignal(Mono.Unix.Native.Signum.SIGTERM), 
        new UnixSignal(Mono.Unix.Native.Signum.SIGINT),
        new UnixSignal(Mono.Unix.Native.Signum.SIGUSR1)
    };

    public UnixExitSignal()
    {
        Task.Factory.StartNew(() => 
        {
            // blocking call to wait for any kill signal
            int index = UnixSignal.WaitAny(signals, -1);

            if (Exit != null)
            {
                Exit(null, EventArgs.Empty);
            }

        });
    }

}