{
	"cmd": "command",
	"requestID": "unique requestID",
	"version": "1.0"
} 
 字段说明:
| 字段名 | 类型 | 说明 | 是否必须 | 
| cmd | string | 请求的命令名称 | 是 | 
| requestID | string | 请求的ID,用于唯一标识每个请求,每个客户端自己保证生成唯一ID,如UUID | 是 | 
| version | string | 协议当前版本,当前为“1.0” | 是 | 
{
	"cmd": "command",
	"requestID": "unique requestID"
} 
 字段说明:
| 字段名 | 类型 | 说明 | 
| cmd | string | 请求的命令名称 | 
| requestID | string | 发送请求中的ID,原封不动返回,使客户端能识别出哪个请求对应的响应 | 
发送打印/预览数据协议(0.x版本)
注:因为打印机质量乘次不齐,建议 1 个 task 使用 一个 document,可以有效避免重打问题;
预览流程0.x:
打印流程(预览流程1.x):
请求协议格式(密文数据,针对菜鸟电子面单)如下:
{
	"cmd": "print",
	"requestID": "123458976",
	"version": "1.0",
	"task": {
		"taskID": "7293666",
		"preview": false,
		"printer": "",
		"previewType": "pdf",
		"firstDocumentNumber": 10,
		"totalDocumentCount": 100,
		"documents": [{
			"documentID": "0123456789",
			"contents": [{
			"encryptedData":"AES:rU904rj6UH2oqfSUb43+Z+XlOkZaULeerkScS5xbmfjZC78uvsMTa3g6l33hRAz/srsk0TObjJaJI5n4tAPV1uv7szIPQGPDhwD6MK+zvTVIfuQCMC8p+cUB5S4FmqDhNE45LRVAlaoaI5YK8QmWK1WorhwnPxOFH4Ws/ApobtzDLDJaW6uu1AMEdAejEhRTWL3B1fRhhcDxc3gX+DZF9jJUB++fb9JZqmocWRu0Fvi/b1BokQx7Xt/N+FpJVRI0//NNUQ9b/W4tqGFIbf2IM/Ez1S5hBru5gKGdFzs99ZgCKqtWa0DnOzrZDXroU1mhurtlulE8QbipInu63fkIwn3h9ZSK0sMyV5Jrk5x3MIJDHeW9pc/Tw4TnKTAU134jl+GbbpYysa0+jBARWRjombeKIFSVfp/zgp15jClClUU1Nz4alTi22LimY2qteQRG6G/rCHiYxPoBRdrtqZZxNSdnKG5yjSdtA2CEL1DJNg1QkFVSSsOuqcHLdrKl6oMR+aUN6wM3GQikmKSU/CH4hWCCXxFaJXvBYoSxZ63GrM/d+l6D4+9+rCxHJoEVsa2E1TMHLUOnN6CweSM+45lcBK19bbCUJDyky6nb1NbxrZGYhmfkrNzE2GN+Cz4iTAgxJlQxd1gVvS4v5nB7qNfb0Uhy9NTopdumxOS7NXFFg3RFdBfAJ0nLGnxECUvUihBC3pwsLGimrUnIF4174m6J6Ga6cQE+Pp1LXgtKf5zWJdWHkm2vQhazcAsQC8JJZFb1ESp1vIAvpy0d0YmGrLLzxWNciHlOa7vguFCVF3UbTFe8r1Mxyym9rqNrZDXWRtBija9yeliMERVFuOTRjlc0PVAzveexQmuD4ESTzMZPtbO0jos1EITKhHcV35Na7E4I7bEe3L2u5yuFuzDA5cc8OA8v761+xOI70bGXUwvFO2kCCiUFEzI9ksLIDTtydBTA94lf4MYH6m0ziRmAhAgcwm5QJFd2G4JzpFIK4+dLuEZamrYUcnHmWzDIg+HYIXh6g3S2maFU7dUtwYoerptOTiVg8FxRlUTx30NDTgjm7ll8vEJXHj7yd/gAO3Vm9P54OSMv8w+pzX3gtCkvthrkjlToT1jMRNJyuJAeSBf5jruzYLS68inlSE/ehT10zhaiBvaCqojZZ2Ux0JQGhbR/nQ==",
			"signature":"19d6f7759487e556ddcdd3d499af087080403277b7deed1a951cc3d9a93c42a7e22ccba94ff609976c5d3ceb069b641f541bc9906098438d362cae002dfd823a8654b2b4f655e96317d7f60eef1372bb983a4e3174cc8d321668c49068071eaea873071ed683dd24810e51afc0bc925b7a2445fdbc2034cdffb12cb4719ca6b7",
                        "templateURL":"http://cloudprint.cainiao.com/template/standard/101/123",
                        "ver":"waybill_print_secret_version_1"
			},
			{
				"data": {
					"value": "测试字段值需要配合自定义区变量名"
				},
				"templateURL": "http://cloudprint.cainiao.com/template/customArea/440439"
			}]
		}]
	}
} 
 请求协议格式(明文数据)如下:
{
	"cmd": "print",
	"requestID": "123458976",
	"version": "1.0",
	"task": {
		"taskID": "7293666",
		"preview": false,
		"printer": "",
		"previewType": "pdf",
		"firstDocumentNumber": 10,
		"totalDocumentCount": 100,
		"documents": [{
			"documentID": "0123456789",
			"contents": [{
				"data": {
					"nick": "张三"
				},
				"templateURL": "http://cloudprint.cainiao.com/template/standard/278250/1"
			},
			{
				"data": {
					"value": "测试字段值需要配合自定义区变量名"
				},
				"templateURL": "http://cloudprint.cainiao.com/template/customArea/440439"
			}]
		}]
	}
} 
 字段说明:
| 字段名 | 类型 | 说明 | 是否必须 | 
| taskID | string | 打印机任务ID,每个打印任务会分配不同的且唯一的ID,在0.x中,默认不允许taskID重复,若重复则直接返回错误 在1.5.0中,当task结构中的idempotent设置为true时,不允许taskID重复,默认允许重复 | 是 | 
| idempotent | bool | 1.5.0版本及以后支持 与taskID搭配使用,当值为true时,taskID不允许重复,默认为false | 否 | 
| notifyType | array | 打印通知类型:“render”, “print” [“render”] : 仅渲染响应 notify [“print”] : 仅出纸响应 notify ?“render”, “print” : 渲染完成会响应 notify && 出纸完成后会响应 notify [] : 不允许 注:如果notifyType没有指定,默认为[“render”, “print”] ??在1.x版本中废弃此字段,总是会进行通知 | 否 | 
| preview | bool | 是否预览.true为预览,false为打印 | 是 | 
| printType | string | 可选dirctPrint或templatePrint 默认为templatePrint,当设置为dirctPrint时,templateURL可以放入PDF的链接进行PDF打印 | 否 | 
| previewType | string | 属性取值“pdf” or “image” 预览模式,是以pdf还是image方式预览,二选一,此属性不是必选,默认以pdf预览。 | 否 | 
| firstDocumentNumber | int | task 起始 document 序号 | 否 | 
| totalDocumentCount | int | task document 总数 | 否 | 
| printer | string | 打印机名,如果为空,会使用默认打印机 | 否 | 
| templateURL | string | 模板文件url | 是 | 
| signature | string | 模板与数据的签名 | 否 | 
| documents | array | 文档数组,每个数据表示一页 | 是 | 
| documentID | string | 文档的唯一ID,对于菜鸟标准面单来讲,就是面单号;如果是自定义模板,需要保证唯一 | 是 | 
| data | Json Object | 模板需要的打印数据 | 是 | 
协议格式如下:
{
    "cmd":"print",
    "requestID":"123458976",
    "taskID":"1",
    "status":"success", //如果是打印,表示打印任务提交成功,如果是预览,表示预览PDF文件生成成功
    "previewURL":"http://127.0.0.1/previewxxx.pdf", //如果是预览,会返回这个属性,表示预览PDF文件的URL地址,如果是打印命令,不返回此属性
//如果是预览并且预览模式是previewType:image,会返回这个属性,表示预览图片的URL地址,如果是打印命令,不返回此属性
   "previewImage": [
    http://127.0.0.1/preview1.jpg,
    http://127.0.0.1/preview2.jpg,
    http://127.0.0.1/preview3.jpg
   ],
//1.x后的菜鸟打印组件版本
"urls"["url1","url2"]
} 
 | 字段名 | 类型 | 说明 | 
| taskID | string | 打印机任务ID,每个打印任务会分配不同的且唯一的ID | 
| status | string | 如果是打印,表示打印任务提交成功,如果是预览,表示预览PDF文件生成成功 | 
| previewURL | string | 可预览的PDF文件URL路径 | 
| previewImage | string[] | 预览image的URL路径,是一个字符串数组 | 
| urls | string[] | 1.x后的菜鸟打印组件版本会在预览时返回 | 
注:
* 如果是打印命令,只是表示将打印任务提交到任务队列,会快速返回。
* 如果是预览命令,且版本为0.x则需要将预览文件生成,才会返回,需要一段等待时间。如果是1.x版本,则会立即返回一条消息表示任务已提交到任务队列,随后当预览文件生成后,会再次返回一个消息并携带文件地址
由于网络协议本身的不可靠性,建议接入时按照以下规范进行,否则可能出现漏打、重复打等情况
打印通知(notifyPrintResult) 0.x版本
此消息总是由菜鸟打印组件向调用方返回
通知协议格式如下:
{
     "cmd":"notifyPrintResult",
     "printer":"中通打印机A",
     "taskID":"1",
     "taskStatus":"printed",
     "printStatus":[
        {
           "documentID”:”9890000112011”,
           "status":"success",
           "msg":"if failed,some tips, if success ,nothing”,
           "detail":"错误信息的补充描述"
        }
    ]
} 
 | 字段名 | 类型 | 说明 | 
| documentID | string | 文档的唯一ID,对于菜鸟标准面单来讲,就是面单号;如果是自定义模板,需要保证唯一 | 
| taskStatus | string | 任务状态: failed : 失败; rendered: 渲染完成 printed : 出纸完成 ?注:当打印出纸之后才会发送通知并且只通知一次 | 
| status | string | 任务状态:success成功;failed 失败,canceled 取消 (当一个任务中的一个文档打印失败,任务中其他的文档打印状态为“canceled”状态) | 
| msg | string | 如果任务状态为成功或挂起为空,如果任务状态为失败,则为失败原因概要。 | 
| detail | string | 错误信息的补充描述 | 
| printer | string | 负责打印的打印机名 | 
| taskID | string | 任务ID,每个打印任务会分配不同的且唯一的ID | 
获取打印机列表(getPrinters)
请求协议格式如下:
{
	"cmd": "getPrinters",
	"requestID": "123458976",
	"version": "1.0"
} 
 响应协议格式如下:
{
	"cmd": "getPrinters",
	"requestID": "123458976",
	"defaultPrinter": "XX快递打印机",
	"printers": [{
		"name": "XX快递打印机"
	},
	{
		"name": "YY物流打印机"
	}]
} 
 | 字段名 | 类型 | 说明 | 
| defaultPrinter | string | 默认打印机 | 
| name | string | 打印机的名字 | 
请求协议格式如下:
{
  "cmd":"getPrinterConfig",
  "printer":"菜鸟打印机",
  "version":"1.0",
  "requestID":"123456789"
} 
 响应协议格式如下:
{
	"cmd": "getPrinterConfig",
	"requestID": "123456789",
	"status": "success/failed",
	"msg": "如果出错,错误原因",
	"printer": {
		"name": "打印机名称",
		"needTopLogo": false,
		"needBottomLogo": false,
		"horizontalOffset": 1,
		"verticalOffset": 2,
		"forceNoPageMargins": true,
		"autoPageSize": false,
		"orientation": 0,
		"autoOrientation": false,
		"paperSize": {
			"width": 100,
			"height": 180
		}
	}
} 
 | 字段名 | 类型 | 说明 | 
| status | string | 标示命令成功或失败,取值“success”或者“failed” | 
| msg | string | 如果出错,错误原因 | 
| printer.name | string | 打印机名称 | 
| printer.needTopLogo | bool | 是否需要模板上联的快递logo true为需要 false为不需要 | 
| printer.needBottomLogo | bool | 是否需要模板下联的快递logo true为需要 false为不需要 | 
| printer.horizontalOffset | float | 水平偏移量 | 
| printer.verticalOffset | float | 垂直偏移量 | 
| printer.forceNoPageMargins | bool | 强制设置页面无空边 true为强制设置页面无空边 false为由打印机驱动决定 | 
| printer.paperSize.width | int | 打印机纸张的宽度,单位是毫米 | 
| printer.paperSize.height | int | 打印机纸张的高度,单位是毫米 | 
| printer. autoPageSize | bool | true:自适应纸张大小 false:不自适应 | 
| printer. orientation | int | 0:纵向 1: 横向 | 
| printer. autoOrientation | bool | true:按照 orientation 适应纸张方向 false:不自适应 | 
请求协议格式如下:
{
	"cmd": "setPrinterConfig",
	"requestID": "123458976",
	"version": "1.0",
	"printer": {
		"name": "菜鸟打印机",
		"needTopLogo": true,
		"needBottomLogo": false,
		"horizontalOffset": 0.5,
		"verticalOffset": 0.7,
		"forceNoPageMargins": true,
		"autoPageSize": false,
		"orientation": 0,
		"autoOrientation": false,
		"paperSize": {
			"width": 100,
			"height": 180
		}
	}
} 
 注:参数说明参考 获取打印机配置(getPrinterConfig)
响应协议格式如下:
{
     "cmd":"setPrinterConfig",
     "requestID":"123458976",
     "status":"success",
     "msg":"if failed ,some tips, if success,nothing"
} 
 | 字段名 | 类型 | 说明 | 
| status | string | 消息处理结果。success:成功;failed:失败 | 
| msg | string | 如果成功,则为空;如果失败,则为失败原因 | 
注:如果要保持某个配置不变,应省略对应的配置字段。
请求协议格式如下:
{
    "cmd":"getTaskStatus",
    "requestID":"123458976",
    "version":"1.0",
    "taskID":[
        "12311",
        "12312"
    ]
} 
 | 字段名 | 类型 | 说明 | 是否必须 | 
| taskID | json数组 | 打印机任务ID列表 | 是 | 
响应协议格式如下:
{
    "cmd":"getTaskStatus",
    "requestID":"123458976",
    "printStatus":[
        {
            "taskID":"12312", 
            "detailStatus":[
              {
                 "documentID":"9890000112011",
                 "status":"success",
                 "msg":"if failed ,some tips, if success or pending nothing",
                 "printer":"中通打印机A"
              }
            ]
        }
    ]
} 
 | 字段名 | 类型 | 说明 | 
| taskID | string | 打印机任务ID,每个打印任务会分配不同的且唯一的ID | 
| documentID | string | 文档的唯一ID,对于菜鸟标准面单来讲,就是面单号;如果是自定义模板,需要保证唯一 | 
| status | string | 任务状态:success成功;failed失败;pending,提交到打印机打印队列 | 
| msg | string | 如果任务状态为成功或挂起为空,如果任务状态为失败,则为失败原因。 | 
| printer | string | 负责打印的打印机名 | 
请求协议格式如下:
{
    "cmd":"getGlobalConfig",
    "requestID":"12345678901",
    "version":"1.0"
} 
 响应协议格式如下:
{
    "cmd":"getGlobalConfig",
    "requestID":"12345678901",
    "status":"success",
    "msg":"return nothing when success, return some tips when failed",
    "notifyOnTaskFailure":true,
    //忽略字体无法显示的问题
    "ignoreFontCanNotDisplay":true
} 
 字段解释:
| 字段名 | 类型 | 说明 | 
| status | string | 表示命令成功或失败,取值“success”或者“failed” | 
| msg | string | 如果出错,错误原因 | 
| notifyOnTaskFailure | bool | 打印任务失败时是否需要通知(弹出对话框提醒用户打印失败原因并默认暂停当前打印机的打印),true为需要,false为不需要 | 
| ignoreFontCanNotDisplay | bool | true表示忽略字体无法显示的问题 false则在字体无法显示时会弹窗报错 | 
请求协议格式如下:
{
    "cmd":"setGlobalConfig",
    "requestID":"12345678901",
    "version":"1.0",
    "notifyOnTaskFailure":true,
    //忽略字体无法显示的问题
    "ignoreFontCanNotDisplay":true
} 
 响应协议格式如下:
{
    "cmd":"setGlobalConfig",
    "requestID":"12345678901",
    "status":"success",
    "msg":"return nothing when success, return some tips when failed"
} 
 字段解释:
| 字段名 | 类型 | 说明 | 
| status | string | 表示命令成功或失败,取值“success”或者“failed” | 
| msg | string | 如果出错,错误原因 | 
| notifyOnTaskFailure | bool | 打印任务失败时是否需要通知(弹出对话框提醒用户打印失败原因并默认暂停当前打印机的打印),true为需要,false为不需要 | 
请求协议格式如下:
{
    "cmd":"getAgentInfo",
    "requestID":"12345678901",
    "version":"1.0"
} 
 响应协议格式如下:
{
    "cmd":"getAgentInfo",
    "requestID":"12345678901",
    "status":"success",
    "msg":"return nothing when success, return some tips when failed",
    "version":"0.2.8.3" 
} 
 字段解释:
| 字段名 | 类型 | 说明 | 
| status | string | 表示命令成功或失败,取值“success”或者“failed” | 
| msg | string | 如果出错,错误原因 | 
| version | string | 版本号 | 
function doConnect()
{
    socket = new WebSocket('ws://localhost:13528');
    //如果是https的话,端口是13529
    //socket = new WebSocket('wss://localhost:13529');
    // 打开Socket
    socket.onopen = function(event)
    {
        // 监听消息
        socket.onmessage = function(event)
        {
            console.log('Client received a message',event);
        };
        // 监听Socket的关闭
        socket.onclose = function(event)
        {
            console.log('Client notified socket has closed',event);
        };
    };
}
/***
 * 
 * 获取请求的UUID,指定长度和进制,如 
 * getUUID(8, 2)   //"01001010" 8 character (base=2)
 * getUUID(8, 10) // "47473046" 8 character ID (base=10)
 * getUUID(8, 16) // "098F4D35"。 8 character ID (base=16)
 *   
 */
function getUUID(len, radix) {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
    var uuid = [], i;
    radix = radix || chars.length; 
    if (len) {
      for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
    } else {
      var r;
      uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
      uuid[14] = '4';
      for (i = 0; i < 36; i++) {
        if (!uuid[i]) {
          r = 0 | Math.random()*16;
          uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
        }
      }
    }
    return uuid.join('');
}
/***
 * 构造request对象
 */
function getRequestObject(cmd){
    var request  = new Object();
    request.requestID=getUUID(8, 16);
    request.version="1.0";
    request.cmd=cmd;
    return request;
}
/***
 * 获取自定义区数据以及模板URL
 * waybillNO 电子面单号
 */
function getCustomAreaData(var waybillNO){
    //获取waybill对应的自定义区的JSON object,此处的ajaxGet函数是伪代码
    var jsonObject = ajaxGet(waybillNO);
    var ret = new Object();
    ret.templateURL=jsonObject.content.templateURL;
    ret.data=jsonObject.content.data;
    return ret;
}
/***
 * 获取电子面单Json 数据
 * waybillNO 电子面单号
 */
function getWaybillJson(var waybillNO){
    //获取waybill对应的json object,此处的ajaxGet函数是伪代码
    var jsonObject = ajaxGet(waybillNO);
    return jsonObject;
}
/**
 * 请求打印机列表demo
 * */
var request  = getRequestObject("getPrinters");
webSocket.send(JSON.stringify(request));
/**
 * 弹窗模式配置打印机
 * */
var request  = getRequestObject("printerConfig");
webSocket.send(JSON.stringify(request));
/**
 * 打印电子面单
 * printer 指定要使用那台打印机
 * waybillArray 要打印的电子面单的数组
 */
function doPrint(var printer,var waybillArray)
{
    var request = getRequestObject("print");    
    request.task = new Object();
    request.task.taskID = getUUID(8,10);
    request.task.preview = false;
    request.task.printer = printer;
    var documents = new Array();
    for(i=0;i<waybillArray.length;i++) {
         var doc = new Object();
         doc.documentID = waybillArray[i];
         var content = new Array();
         var waybillJson = getWaybillJson(waybillArray[i]);
         var customAreaData = getCustomAreaData(waybillArray[i]);
         content.push(waybillJson,customAreaData);
         doc.content = content;
         documents.push(doc);
    }
    request.task.documents=documents;
    socket.send(JSON.stringify(request));
}
/**
 * 响应请求demo
 * */
websocket.onmessage = function(event){   
    var response = eval(event.data);
    if (response.cmd == 'getPrinters') {
        getPrintersHandler(response);//处理打印机列表
    } else if (response.cmd == 'printerConfig') {
        printConfigHandler(response);
    } 
}; 
 c++ Demo使用动态链接库的方式。
PrinterManager提供以下接口,调用约定 stdcall 方式:
int initPrinterManager(const char *url); void setRecvDataCallback(_onMessage_func func); int sendMessage(const char *message); int closePrinterManager();
说明:需要输入url的地址才能正常调用initPrinterManager,否则报错;
参数:const char *url指向WEBSOCKET的地址,如“ws://127.0.0.1:13528”
返回值:整型,成功返回0,返回-1表示初始化失败,返回-2表示重复初始化错误,返回-3表示未输入url
注意:每载入一次dll,只调用一次initPrinterManager(),重复调用返回-1.
void setRecvDataCallback(_onMessage_func func);
功能:设定回调函数,此回调函数作用:如果接收到数据则调用回调函数
返回值:无
传入参数:_onMessage_func func:函数指针,类型为typedef void(_onMessage_func)(const char message),
C++中对应回调函数例子:
void handle_message(const char* message)
{
printf(“>>> %s\n”, message);
}
int sendMessage(const char *message);
功能:发送数据给打印客户端
返回值:整型,成功返回0,返回-1表示websocket未连接
传入参数:const char *message:字符串类型(传入的字符串必须确保已经是UTF-8编码)
int closePrinterManager()
功能:关闭websocket
返回值:整型,成功返回0,返回-1表示websocket在调用前已关闭或未初始化
注意:不要重复关闭,否则返回-1.
以获取打印机列为例:
获取打印机列表命令如下:
{
    "cmd":"getPrinters",
    "requestID":"123458976",
    "version":"1.0"
} 
 DEMO中采用cJSON开源库作为生成JSON数据的工具:
string getRequestObject()
{
    cJSON *root;
    root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "cmd", "getPrinters");
    cJSON_AddStringToObject(root, "requestID", "123458976");
    cJSON_AddStringToObject(root, "version", "1.0");
    string str = string(cJSON_Print(root));
    cJSON_Delete(root);
    return str;
} 
 构造打印指令代码如下:
string getPrintRequestObject()
{
    cJSON *root;
    root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "cmd", "print");
    cJSON_AddStringToObject(root, "requestID", "123458976");
    cJSON_AddStringToObject(root, "version", "1.0");
    cJSON *task = cJSON_CreateObject();
    cJSON_AddStringToObject(task, "taskID", "1");
    cJSON_AddFalseToObject(task, "preview");
    cJSON *documents = cJSON_CreateObject();
    cJSON_AddStringToObject(documents, "ducumentID", "9890106027");
    cJSON *contents = cJSON_CreateArray();
    //data为电子面单数据,TOP接口返回数据可直接获得
    cJSON_AddItemToArray(contents, cJSON_CreateString(data.c_str()));
    cJSON_AddItemToObject(documents, "contents", contents);
    cJSON_AddItemToObject(task, "documents", documents);
    cJSON_AddItemToObject(root, "task", task);
    //调用cJSON_PrintBuffered则去除换行符
    string str = string(cJSON_Print(root));
    cJSON_Delete(root);
    return str;
} 
 java使用websocket需要引入第三方库 下载地址 。
<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.3.0</version>
</dependency> 
 自己创建一个websocket管理类,需要继承自第三方类库的WebSocketClient:
import java.net.URI;
import java.net.URISyntaxException;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_17;
import org.java_websocket.handshake.ServerHandshake;
public class WebSocketClientManager extends WebSocketClient {
    static WebSocketClientManager webSocket = null;
    public static void main(String[] args) throws URISyntaxException {
        String uri = "ws://127.0.0.1:13528";
        webSocket = new WebSocketClientManager(new URI(uri), new Draft_17());
        //建立连接
        webSocket.connect();
    }
    public WebSocketClientManager(URI serverUri, Draft draft) {
        super(serverUri, draft);
    }
    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        //获取打印机列表
        String getPrinterListCmd = "{\"requestID\":\"12345678901234567890\",\"verson\":\"1.0\",\"cmd\":\"getPrinters\"}";
        webSocket.send(getPrinterListCmd);
        //发送打印任务
        String printCmd = "打印任务报文,内容过长此处不粘贴";
        webSocket.send(printCmd);
    }
    //WebSocket回调函数
    @Override
    public void onMessage(String message) {
        //TODO 对打印服务返回的数据进行处理
        System.out.println(message);
    }
    @Override
    public void onClose(int i, String s, boolean b) {
    }
    @Override
    public void onError(Exception e) {
    }
} 
 使用C#官方提供的 websocket 库,根据上面说明的菜鸟打印协议进行开发。