jupyter notebook的通信

提示用戶輸入一段代碼,當(dāng)用戶輸入以后執(zhí)行。這種模式經(jīng)常被稱為REPL(交互式開發(fā)環(huán)境)瞻讽,或者Read-Eval-Print-Loop(讀取﹣求值﹣輸出循環(huán)).jupyter notebook就是這樣一種在web端的交互式開發(fā)環(huán)境鸳吸,如下:


jupyter notebook示例

對(duì)應(yīng).ipynb文件的內(nèi)容:

{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pi is rough3.142608\n"
     ]
    }
   ],
   "source": [
    "import scala.math.random\n",
    "import org.apache.spark._\n",
    "val slices = 10\n",
    "val n = math.min(100000L * slices, Int.MaxValue).toInt\n",
    "val count = sc.parallelize(1 until n, slices).map{ i =>\n",
    "                                                val x = random*2 - 1\n",
    "                                                val y = random*2 -1\n",
    "                                                if (x*x + y*y <1) 1 else 0\n",
    "                                                }.reduce(_+_)\n",
    "println(\"pi is rough\" + 4.0*count/n)"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Apache Toree - Scala",
   "language": "scala",
   "name": "apache_toree_scala"
  },
  "language_info": {
   "name": "scala",
   "version": "2.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}

IPython 內(nèi)核 所有其它接口,包括Notebook速勇,Qt控制臺(tái)晌砾,ipython控制臺(tái)和其它第三方接口,都使用IPython內(nèi)核烦磁。IPython內(nèi)核是一個(gè)獨(dú)立的進(jìn)程养匈,負(fù)責(zé)執(zhí)行用戶代碼和其它事情,例如計(jì)算可能的補(bǔ)全都伪。前端處理器呕乎,例如notebook和Qt控制臺(tái),使用ZeroMQ傳輸JSON消息與IPython內(nèi)核通信陨晶,前端處理器與IPython內(nèi)核通信使用的協(xié)議詳細(xì)描述請(qǐng)參考Jupyter 消息

notebook簡(jiǎn)單通信圖

Notebook 前端處理器做一些額外的事情猬仁。除了運(yùn)行你的代碼,它還儲(chǔ)存代碼和輸出先誉、以及markdown注釋在一個(gè)可編輯的文檔中湿刽,我們稱這個(gè)文檔為一個(gè)notebook。當(dāng)你保存這個(gè)文檔時(shí)褐耳,它會(huì)從你的瀏覽器發(fā)送到notebook服務(wù)器诈闺,服務(wù)器將文檔保存為.ipynb為拓展名的JSON格式文件,notebook服務(wù)器而不是內(nèi)核漱病,負(fù)責(zé)保存和載入notebook买雾,因此你可以編輯notebook即使你沒(méi)有那種編程語(yǔ)言的內(nèi)核,你僅僅不能運(yùn)行notebook中的代碼杨帽。內(nèi)核不知道notebook文檔任何事情漓穿,它只是在用戶運(yùn)行代碼時(shí)獲取用戶發(fā)送的代碼并執(zhí)行。導(dǎo)出notebooks到其他格式 Jupyter中的工具Nbconvert可以將notebook文件轉(zhuǎn)換到其它格式注盈,例如HTML晃危,LaTex.
使用nbconvert和HTML導(dǎo)出器。當(dāng)你輸入一個(gè)網(wǎng)址老客,它從輸入的網(wǎng)址獲取notebook僚饭,然后將其轉(zhuǎn)換為HTML格式,并將HTML呈現(xiàn)給你胧砰。

jupyter

Python Notebook中輸入的代碼經(jīng)由瀏覽器發(fā)送給Web服務(wù)器鳍鸵,再由Web服務(wù)器發(fā)送消息到IPython的Kernel執(zhí)行代碼,在Kernel中執(zhí)行代碼所產(chǎn)生的輸出會(huì)再發(fā)送給Web服務(wù)器從而發(fā)送給瀏覽器尉间,完成整個(gè)運(yùn)行過(guò)程偿乖。Web服務(wù)器和Kernel之間采用ZeroMQ進(jìn)行通信击罪。下面為其通信的示意圖:
通信示意圖

圖中,Kernel經(jīng)由綠色的DEAL-ROUTER通道接收來(lái)自Web服務(wù)器的命令消息贪薪,并返回應(yīng)答消息媳禁。通過(guò)紅色的PUB-SUB通道傳輸被執(zhí)行代碼所產(chǎn)生的輸出信息。
在Kernel中画切,用戶代碼在一個(gè)用戶環(huán)境(字典)中執(zhí)行竣稽,通常無(wú)法獲得關(guān)于Kernel的信息。但是由于用戶代碼和Kernel在同一進(jìn)程中執(zhí)行霍弹,因此我們可以通過(guò)一些特殊的代碼研究Kernel是如何接收毫别、運(yùn)行并返回消息的。
兩種思路:
一庞萍、從websocket入手
打開一個(gè)新的notebook: http://127.0.0.1:5000/notebooks/Untitled1.ipynb
從chrome調(diào)試面板的Network可以看到拧烦,有個(gè)websocket:ws://127.0.0.1:5000/api/kernels/d13a50b0-6baa-4d5e-8564-95f224daxxxx/channels?session_id=F552491A7C0448A2B5567DE1A71Cxxxx钝计,代碼經(jīng)由它往后端發(fā)送,也經(jīng)由它接收后臺(tái)返回的信息
當(dāng)我們運(yùn)行上頭的print("hello world")時(shí)齐佳,往后臺(tái)發(fā)送如下數(shù)據(jù)

{
"header":
{
"msg_id":"D8FA79DCD7D140DF8F9C37EE15D9FD6D",
"username":"username",
"session":"91608A811CAE4FA6A5E09D37AF68DF32",
"msg_type":"execute_request",
"version":"5.0"
},
"metadata":{},
"content":
{
"code":"print(\"hello world\")",
"silent":false,
"store_history":true,
"user_expressions":{},
"allow_stdin":true,
"stop_on_error":true
},
"buffers":[],
"parent_header":{},
"channel":"shell"
}

接下來(lái)有5個(gè)frames:

{
"parent_header": 
{
"username": "username",
 "session": "91608A811CAE4FA6A5E09D37AF68DF32", 
"version": "5.0",
 "msg_id": "D8FA79DCD7D140DF8F9C37EE15D9FD6D",
 "msg_type": "execute_request"
}, 
"msg_type": "status",
 "msg_id": "ce11828e-1c2a-4254-962f-2db9e2ff3353", 
"content": 
{
"execution_state": "busy"
}, 
"header": 
{
"username": "root",
 "version": "5.0", 
"msg_type": "status",
 "msg_id": "ce11828e-1c2a-4254-962f-2db9e2ff3353", 
"session": "604a11a4-14eb-4f8a-b32d-044d4c195bf3",
 "date": "2017-12-03T20:05:06.816757"
}, 
"channel": "iopub",
 "buffers": [], 
"metadata": 
{
"timestamp": "1512302706811"
}
}
{
"parent_header":
 {
"username": "username", 
"session": "91608A811CAE4FA6A5E09D37AF68DF32", 
"version": "5.0",
 "msg_id": "D8FA79DCD7D140DF8F9C37EE15D9FD6D",
 "msg_type": "execute_request"
}, 
"msg_type": "execute_input",
 "msg_id": "116696e7-befa-40c7-98c1-88e32e1e9b63",
 "content": 
{
"execution_count": 1, 
"code": "print(\"hello world\")"
}, 
"header":
 {
"username": "root",
 "version": "5.0",
 "msg_type": "execute_input",
 "msg_id": "116696e7-befa-40c7-98c1-88e32e1e9b63", 
"session": "604a11a4-14eb-4f8a-b32d-044d4c195bf3", 
"date": "2017-12-03T20:05:06.829865"
}, 
"channel": "iopub", 
"buffers": [],
 "metadata": 
{
"timestamp": "1512302706826"
}
}
{
"parent_header": 
{
"username": "username",
 "session": "91608A811CAE4FA6A5E09D37AF68DF32", 
"version": "5.0", "msg_id": "D8FA79DCD7D140DF8F9C37EE15D9FD6D", 
"msg_type": "execute_request"
}, 
"msg_type": "stream",
 "msg_id": "d3c9ffa1-108f-4ea2-88db-100985fe23d0",
 "content": 
{
"text": "hello world", "name": "stdout"
}, 
"header": 
{
"username": "root", 
"version": "5.0", 
"msg_type": "stream",
 "msg_id": "d3c9ffa1-108f-4ea2-88db-100985fe23d0",
 "session": "604a11a4-14eb-4f8a-b32d-044d4c195bf3", 
"date": "2017-12-03T20:05:07.071811"
}, 
"channel": "iopub",
 "buffers": [],
 "metadata": 
{
"timestamp": "1512302707065"
}
}
{
"parent_header":
 {
"username": "username", 
"session": "91608A811CAE4FA6A5E09D37AF68DF32",
 "version": "5.0", 
"msg_id": "D8FA79DCD7D140DF8F9C37EE15D9FD6D",
 "msg_type": "execute_request"
},
 "msg_type": "execute_reply",
 "msg_id": "6ee99d0d-9c92-41ce-be06-39241719f321",
 "content": 
{
"status": "ok", 
"execution_count": 1, 
"payload": [],
 "user_expressions": {}
}, 
"header":
 {
"username": "root",
 "version": "5.0",
 "msg_type": "execute_reply",
 "msg_id": "6ee99d0d-9c92-41ce-be06-39241719f321",
 "session": "604a11a4-14eb-4f8a-b32d-044d4c195bf3",
 "date": "2017-12-03T20:05:07.097685"
}, 
"channel": "shell",
 "buffers": [], 
"metadata": 
{
"timestamp": "1512302707094"
}
}
{
"parent_header": 
{
"username": "username",
 "session": "91608A811CAE4FA6A5E09D37AF68DF32",
 "version": "5.0",
 "msg_id": "D8FA79DCD7D140DF8F9C37EE15D9FD6D", 
"msg_type": "execute_request"
}, 
"msg_type": "status",
 "msg_id": "32857f80-db87-4775-9350-fe009a8e9c18",
 "content": {
"execution_state": "idle"
}, 
"header":
 {
"username": "root", 
"version": "5.0", 
"msg_type": "status",
 "msg_id": "32857f80-db87-4775-9350-fe009a8e9c18",
 "session": "604a11a4-14eb-4f8a-b32d-044d4c195bf3", 
"date": "2017-12-03T20:05:07.098384"
},
 "channel": "iopub",
 "buffers": [], 
"metadata": 
{
"timestamp": "1512302707095"
}
}
chrome/Network/WS/Frames

在支持WebSocket的瀏覽器中私恬,在創(chuàng)建socket之后×段猓可以通過(guò)onopen本鸣,onmessage,onclose和onerror四個(gè)事件實(shí)現(xiàn)對(duì)socket進(jìn)行響應(yīng)

一個(gè)簡(jiǎn)單的 示例

var ws = new WebSocket(“ws://localhost:8080”);

ws.onopen = function()

{  console.log(“open”);

  ws.send(“hello”);

};

ws.onmessage = function(evt)

{

  console.log(evt.data)

};

ws.onclose = function(evt)

{

  console.log(“WebSocketClosed!”);

};

ws.onerror = function(evt)

{

  console.log(“WebSocketError!”);

};

1.var ws = new WebSocket(“ws://localhost:8080”);

申請(qǐng)一個(gè)WebSocket對(duì)象硅蹦,參數(shù)是需要連接的服務(wù)器端的地址荣德,同http協(xié)議使用http://開頭一樣,WebSocket協(xié)議的URL使用ws://開頭童芹,另外安全的WebSocket協(xié)議使用wss://開頭涮瞻。

ws.send(“hello”);
用于將消息發(fā)送到服務(wù)端
2.ws.onopen = function() { console.log(“open”)};

當(dāng)websocket創(chuàng)建成功時(shí),即會(huì)觸發(fā)onopen事件
3.ws.onmessage = function(evt) { console.log(evt.data) };
當(dāng)客戶端收到服務(wù)端發(fā)來(lái)的消息時(shí)假褪,會(huì)觸發(fā)onmessage事件署咽,參數(shù)evt.data中包含server傳輸過(guò)來(lái)的數(shù)據(jù)
4.ws.onclose = function(evt) { console.log(“WebSocketClosed!”); };

當(dāng)客戶端收到服務(wù)端發(fā)送的關(guān)閉連接的請(qǐng)求時(shí),觸發(fā)onclose事件
5.ws.onerror = function(evt) { console.log(“WebSocketError!”); };
如果出現(xiàn)連接生音,處理宁否,接收,發(fā)送數(shù)據(jù)失敗的時(shí)候就會(huì)觸發(fā)onerror事件
我們可以看出所有的操作都是采用事件的方式觸發(fā)的缀遍,這樣就不會(huì)阻塞UI慕匠,使得UI有更快的響應(yīng)時(shí)間,得到更好的用戶體驗(yàn)域醇。
二台谊、從頁(yè)面入手
在stack overflow里找到解答:

var handle_output = function (data) {console.log(data);}
//callbacks.iopub.output is used to get the data from execute
var callbacks = {
            iopub : {output : handle_output,}
}
//(read the source F12->static/notebook/js/services/kernels/kernel.js)
//kernel.js/717th lines Kernel.prototype.execute
var kernel = IPython.notebook.kernel;
kernel.execute("print('hello')",callbacks)

kernel.js的function:

// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
define('services/kernels/kernel',[
    'jquery',
    'base/js/utils',
    './comm',
    './serialize',
    'base/js/events'
], function($, utils, comm, serialize, events) {
    "use strict";

    /**
     * A Kernel class to communicate with the Python kernel. This
     * should generally not be constructed directly, but be created
     * by.  the `Session` object. Once created, this object should be
     * used to communicate with the kernel.
     * 
     * Preliminary documentation for the REST API is at
     * https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#kernels-api
     * 
     * @class Kernel
     * @param {string} kernel_service_url - the URL to access the kernel REST api
     * @param {string} ws_url - the websockets URL
     * @param {string} name - the kernel type (e.g. python3)
     */
    var Kernel = function (kernel_service_url, ws_url, name) {
        this.events = events;

        this.id = null;
        this.name = name;
        this.ws = null;

        this.kernel_service_url = kernel_service_url;
        this.kernel_url = null;
        this.ws_url = ws_url || utils.get_body_data("wsUrl");
        if (!this.ws_url) {
            // trailing 's' in https will become wss for secure web sockets
            this.ws_url = location.protocol.replace('http', 'ws') + "http://" + location.host;
        }

        this.username = "username";
        this.session_id = utils.uuid();
        this._msg_callbacks = {};
        this._msg_queue = Promise.resolve();
        this.info_reply = {}; // kernel_info_reply stored here after starting

        if (typeof(WebSocket) !== 'undefined') {
            this.WebSocket = WebSocket;
        } else if (typeof(MozWebSocket) !== 'undefined') {
            this.WebSocket = MozWebSocket;
        } else {
            alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox ≥ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
        }
        
        this.bind_events();
        this.init_iopub_handlers();
        this.comm_manager = new comm.CommManager(this);
        
        this.last_msg_id = null;
        this.last_msg_callbacks = {};

        this._autorestart_attempt = 0;
        this._reconnect_attempt = 0;
        this.reconnect_limit = 7;
        
        this._pending_messages = [];
    };

    /**
     * @function _get_msg
     */
    Kernel.prototype._get_msg = function (msg_type, content, metadata, buffers) {

        return msg;
    };

    /**
     * @function bind_events
     */
    Kernel.prototype.bind_events = function () {
       
    };

    /**
     * Initialize the iopub handlers.
     *
     * @function init_iopub_handlers
     */
    Kernel.prototype.init_iopub_handlers = function () {
      
    };

    /**
     * GET /api/kernels
     *
     * Get the list of running kernels.
     *
     * @function list
     * @param {function} [success] - function executed on ajax success
     * @param {function} [error] - functon executed on ajax error
     */
    Kernel.prototype.list = function (success, error) {
    
    };

    /**
     * POST /api/kernels
     *
     * Start a new kernel.
     *
     * In general this shouldn't be used -- the kernel should be
     * started through the session API. If you use this function and
     * are also using the session API then your session and kernel
     * WILL be out of sync!
     *
     * @function start
     * @param {params} [Object] - parameters to include in the query string
     * @param {function} [success] - function executed on ajax success
     * @param {function} [error] - functon executed on ajax error
     */
    Kernel.prototype.start = function (params, success, error) {
        return url;
    };

    /**
     * GET /api/kernels/[:kernel_id]
     *
     * Get information about the kernel.
     *
     * @function get_info
     * @param {function} [success] - function executed on ajax success
     * @param {function} [error] - functon executed on ajax error
     */
    Kernel.prototype.get_info = function (success, error) {
    };

    /**
     * DELETE /api/kernels/[:kernel_id]
     *
     * Shutdown the kernel.
     *
     * If you are also using sessions, then this function shoul NOT be
     * used. Instead, use Session.delete. Otherwise, the session and
     * kernel WILL be out of sync.
     *
     * @function kill
     * @param {function} [success] - function executed on ajax success
     * @param {function} [error] - functon executed on ajax error
     */
    Kernel.prototype.kill = function (success, error) {

    };

    /**
     * POST /api/kernels/[:kernel_id]/interrupt
     *
     * Interrupt the kernel.
     *
     * @function interrupt
     * @param {function} [success] - function executed on ajax success
     * @param {function} [error] - functon executed on ajax error
     */
    Kernel.prototype.interrupt = function (success, error) {

    };

    Kernel.prototype.restart = function (success, error) {
        /**
         * POST /api/kernels/[:kernel_id]/restart
         *
         * Restart the kernel.
         *
         * @function interrupt
         * @param {function} [success] - function executed on ajax success
         * @param {function} [error] - functon executed on ajax error
         */

    };

    Kernel.prototype.reconnect = function () {

    };

    Kernel.prototype._on_success = function (success) {
        /**
         * Handle a successful AJAX request by updating the kernel id and
         * name from the response, and then optionally calling a provided
         * callback.
         *
         * @function _on_success
         * @param {function} success - callback
         */

    };

    Kernel.prototype._on_error = function (error) {
        /**
         * Handle a failed AJAX request by logging the error message, and
         * then optionally calling a provided callback.
         *
         * @function _on_error
         * @param {function} error - callback
         */

    };

    Kernel.prototype._kernel_created = function (data) {
        /**
         * Perform necessary tasks once the kernel has been started,
         * including actually connecting to the kernel.
         *
         * @function _kernel_created
         * @param {Object} data - information about the kernel including id
         */

    };

    Kernel.prototype._kernel_connected = function () {
        /**
         * Perform necessary tasks once the connection to the kernel has
         * been established. This includes requesting information about
         * the kernel.
         *
         * @function _kernel_connected
         */

    };

    Kernel.prototype._kernel_dead = function () {
        /**
         * Perform necessary tasks after the kernel has died. This closing
         * communication channels to the kernel if they are still somehow
         * open.
         *
         * @function _kernel_dead
         */

    };

    Kernel.prototype.start_channels = function () {
        /**
         * Start the websocket channels.
         * Will stop and restart them if they already exist.
         *
         * @function start_channels
         */
    };

    Kernel.prototype._ws_opened = function (evt) {
        /**
         * Handle a websocket entering the open state,
         * signaling that the kernel is connected when websocket is open.
         *
         * @function _ws_opened
         */

    };

    Kernel.prototype._ws_closed = function(ws_url, error) {
        /**
         * Handle a websocket entering the closed state.  If the websocket
         * was not closed due to an error, try to reconnect to the kernel.
         *
         * @function _ws_closed
         * @param {string} ws_url - the websocket url
         * @param {bool} error - whether the connection was closed due to an error
         */

    };
    
    Kernel.prototype._schedule_reconnect = function () {
        /**
         * function to call when kernel connection is lost
         * schedules reconnect, or fires 'connection_dead' if reconnect limit is hit
         */

    };
    
    Kernel.prototype.stop_channels = function () {
        /**
         * Close the websocket. After successful close, the value
         * in `this.ws` will be null.
         *
         * @function stop_channels
         */

    };

    Kernel.prototype.is_connected = function () {
        /**
         * Check whether there is a connection to the kernel. This
         * function only returns true if websocket has been
         * created and has a state of WebSocket.OPEN.
         *
         * @function is_connected
         * @returns {bool} - whether there is a connection
         */
        // if any channel is not ready, then we're not connected

    };

    Kernel.prototype.is_fully_disconnected = function () {
        /**
         * Check whether the connection to the kernel has been completely
         * severed. This function only returns true if all channel objects
         * are null.
         *
         * @function is_fully_disconnected
         * @returns {bool} - whether the kernel is fully disconnected
         */
        return (this.ws === null);
    };
    
    Kernel.prototype._send = function(msg) {
      /**
       * Send a message (if the kernel is connected) or queue the message for future delivery
       *
       * Pending messages will automatically be sent when a kernel becomes connected.
       *
       * @function _send
       * @param msg
       */

    }
    
    Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata, buffers) {
        /**
         * Send a message on the Kernel's shell channel
         *
         * If the kernel is not connected, the message will be buffered.
         * 
         * @function send_shell_message
         */
        return msg.header.msg_id;
    };

    Kernel.prototype.kernel_info = function (callback) {
        /**
         * Get kernel info
         *
         * @function kernel_info
         * @param callback {function}
         *
         * When calling this method, pass a callback function that expects one argument.
         * The callback will be passed the complete `kernel_info_reply` message documented
         * [here](https://jupyter-client.readthedocs.io/en/latest/messaging.html#kernel-info)
         */
    };

    Kernel.prototype.comm_info = function (target_name, callback) {
        /**
         * Get comm info
         *
         * @function comm_info
         * @param callback {function}
         *
         * When calling this method, pass a callback function that expects one argument.
         * The callback will be passed the complete `comm_info_reply` message documented
         * [here](https://jupyter-client.readthedocs.io/en/latest/messaging.html#comm_info)
         */

    };

    Kernel.prototype.inspect = function (code, cursor_pos, callback) {
        /**
         * Get info on an object
         *
         * When calling this method, pass a callback function that expects one argument.
         * The callback will be passed the complete `inspect_reply` message documented
         * [here](https://jupyter-client.readthedocs.io/en/latest/messaging.html#object-information)
         *
         * @function inspect
         * @param code {string}
         * @param cursor_pos {integer}
         * @param callback {function}
         */

    };

    Kernel.prototype.execute = function (code, callbacks, options) {
        /**
         * Execute given code into kernel, and pass result to callback.
         *
         * @async
         * @function execute
         * @param {string} code
         * @param [callbacks] {Object} With the following keys (all optional)
         *      @param callbacks.shell.reply {function}
         *      @param callbacks.shell.payload.[payload_name] {function}
         *      @param callbacks.iopub.output {function}
         *      @param callbacks.iopub.clear_output {function}
         *      @param callbacks.input {function}
         * @param {object} [options]
         *      @param [options.silent=false] {Boolean}
         *      @param [options.user_expressions=empty_dict] {Dict}
         *      @param [options.allow_stdin=false] {Boolean} true|false
         *
         * @example
         *
         * The options object should contain the options for the execute
         * call. Its default values are:
         *
         *      options = {
         *        silent : true,
         *        user_expressions : {},
         *        allow_stdin : false
         *      }
         *
         * When calling this method pass a callbacks structure of the
         * form:
         *
         *      callbacks = {
         *       shell : {
         *         reply : execute_reply_callback,
         *         payload : {
         *           set_next_input : set_next_input_callback,
         *         }
         *       },
         *       iopub : {
         *         output : output_callback,
         *         clear_output : clear_output_callback,
         *       },
         *       input : raw_input_callback
         *      }
         *
         * Each callback will be passed the entire message as a single
         * arugment.  Payload handlers will be passed the corresponding
         * payload and the execute_reply message.
         */
        return this.send_shell_message("execute_request", content, callbacks);
    };

    /**
     * When calling this method, pass a function to be called with the
     * `complete_reply` message as its only argument when it arrives.
     *
     * `complete_reply` is documented
     * [here](https://jupyter-client.readthedocs.io/en/latest/messaging.html#complete)
     *
     * @function complete
     * @param code {string}
     * @param cursor_pos {integer}
     * @param callback {function}
     */
    Kernel.prototype.complete = function (code, cursor_pos, callback) {

        return this.send_shell_message("complete_request", content, callbacks);
    };

    /**
     * @function send_input_reply
     */
    Kernel.prototype.send_input_reply = function (input) {
        return msg.header.msg_id;
    };

    /**
     * @function register_iopub_handler
     */
    Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
        this._iopub_handlers[msg_type] = callback;
    };

    /**
     * Get the iopub handler for a specific message type.
     *
     * @function get_iopub_handler
     */
    Kernel.prototype.get_iopub_handler = function (msg_type) {
        return this._iopub_handlers[msg_type];
    };

    /**
     * Get callbacks for a specific message.
     *
     * @function get_callbacks_for_msg
     */
    Kernel.prototype.get_callbacks_for_msg = function (msg_id) {

    };

    /**
     * Clear callbacks for a specific message.
     *
     * @function clear_callbacks_for_msg
     */
    Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
        if (this._msg_callbacks[msg_id] !== undefined ) {
            delete this._msg_callbacks[msg_id];
        }
    };
    
    /**
     * @function _finish_shell
     */
    Kernel.prototype._finish_shell = function (msg_id) {

    };

    /**
     * @function _finish_iopub
     */
    Kernel.prototype._finish_iopub = function (msg_id) {

    };
    
    /**
     * Set callbacks for a particular message.
     * Callbacks should be a struct of the following form:
     * shell : {
     * 
     * }
     *
     * @function set_callbacks_for_msg
     */
    Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {

    };
    
    Kernel.prototype._handle_ws_message = function (e) {

    };

    Kernel.prototype._finish_ws_message = function (msg) {

    };
    
    Kernel.prototype._handle_shell_reply = function (reply) {
        return promise;
    };

    /**
     * @function _handle_payloads
     */
    Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
        return Promise.all(promise);
    };

    /**
     * @function _handle_status_message
     */
    Kernel.prototype._handle_status_message = function (msg) {
       
    };
    
    /**
     * Handle clear_output message
     *
     * @function _handle_clear_output
     */
    Kernel.prototype._handle_clear_output = function (msg) {

    };

    /**
     * handle an output message (execute_result, display_data, etc.)
     *
     * @function _handle_output_message
     */
    Kernel.prototype._handle_output_message = function (msg) {

    };

    /**
     * Handle an input message (execute_input).
     *
     * @function _handle_input message
     */
    Kernel.prototype._handle_input_message = function (msg) {

    };

    /**
     * Dispatch IOPub messages to respective handlers. Each message
     * type should have a handler.
     *
     * @function _handle_iopub_message
     */
    Kernel.prototype._handle_iopub_message = function (msg) {

    };

    /**
     * @function _handle_input_request
     */
    Kernel.prototype._handle_input_request = function (request) {

    };

    return {'Kernel': Kernel};
});

參考文章:
http://blog.just4fun.site/jupyter-notebook-architecture.html
http://blog.just4fun.site/jupyter-notebook-architecture-hack.html
https://www.tuicool.com/articles/naqIza
http://flamepeak.com/2016/09/12/Jupyter-official-docs-translate-20160912/
https://jupyter-client.readthedocs.io/en/latest/messaging.html#messaging
http://jupyter-notebook.readthedocs.io/en/stable/comms.html
http://hyry.dip.jp/tech/slice/slice.html/36
http://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Connecting%20with%20the%20Qt%20Console.html?highlight=messaging#The-Frontend/Kernel-Model
https://github.com/junjunwudi/zmq-pykernel
https://media.readthedocs.org/pdf/jupyter-notebook/4.x/jupyter-notebook.pdf
https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#create_new_notebook
https://stackoverflow.com/questions/26435653/how-do-i-embed-an-ipython-notebook-in-an-iframe-new
http://www.tornadoweb.org/en/stable/web.html#request-handlers
http://jupyter-client.readthedocs.io/en/latest/messaging.html#custom-messages
http://jupyter-notebook.readthedocs.io/en/latest/extending/handlers.html
http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml
http://Check.torproject.org
https://gist.github.com/disarticulate/d06069ff3e71cf828e5329beab8cb084
https://stackoverflow.com/questions/31357718/ipython-javascript-client-api/42418784#42418784
https://www.cnblogs.com/lxtblogs/p/4947898.html
http://jupyter-client.readthedocs.io/en/latest/messaging.html
http://jupyter-notebook.readthedocs.io/en/latest/frontend_config.html#configuring-the-notebook-frontend
http://ipython.org/ipython-doc/stable/development/messaging.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蓉媳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子青伤,更是在濱河造成了極大的恐慌督怜,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狠角,死亡現(xiàn)場(chǎng)離奇詭異号杠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)丰歌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門姨蟋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人立帖,你說(shuō)我怎么就攤上這事眼溶。” “怎么了晓勇?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵堂飞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我绑咱,道長(zhǎng)绰筛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任描融,我火速辦了婚禮铝噩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘窿克。我一直安慰自己骏庸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布年叮。 她就那樣靜靜地躺著具被,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谋右。 梳的紋絲不亂的頭發(fā)上硬猫,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音改执,去河邊找鬼啸蜜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛辈挂,可吹牛的內(nèi)容都是我干的衬横。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼终蒂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蜂林!你這毒婦竟也來(lái)了遥诉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤噪叙,失蹤者是張志新(化名)和其女友劉穎矮锈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睁蕾,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苞笨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了子眶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瀑凝。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖臭杰,靈堂內(nèi)的尸體忽然破棺而出粤咪,到底是詐尸還是另有隱情,我是刑警寧澤渴杆,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布寥枝,位于F島的核電站,受9級(jí)特大地震影響磁奖,放射性物質(zhì)發(fā)生泄漏脉顿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一点寥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧来吩,春花似錦敢辩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至怠苔,卻和暖如春同廉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柑司。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工迫肖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人攒驰。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓蟆湖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親玻粪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子隅津,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容