web应用程序访问串口

https://github.com/tylermenezes/SerialServe

https://github.com/straend/SerialWebsocket

http://www.cnblogs.com/lcchuguo/p/4007392.html

Java Applet读写client串口——终极篇

測试环境:

SDK:Oracle JRockit for Java version 6, Java Communication for Windows 2.0

OS:WINDOWS7

外设:串口条形码扫描枪

Server:Tomcat6

看了网上良莠不齐的关于Applet訪问串口的文章,总结起来所关注的问题无外乎下面3个:

1.    三个文件(comm.jar、javax.comm.properties和win32com.dll)究竟应该存放在什么文件夹中?

2.    怎样实现代码?

3.    Applet究竟应该这么部署?

一.关于第一个问题,网上大致是这样写的:

a)      将javax.comm.properties文件放在$JAVA_HOME/lib文件夹中;

b)      将win32comm.dll文件放在$JAVA_HOME/bin文件夹中;

c)      将comm.jar文件放在$JAVA_HOME/lib/ext文件夹中;

先不去讨论这些文件应不应该放在这些文件夹中,单从可行性方面讨论就不太符合WEB应用程序的做法。首先您不可能预知有多少client的存在,就算您预先知道也不可能在每一个client计算机上部署上述3个文件。好,您说能够提供使用手冊引导用户下载文件并依照手冊将上述文件部署到指定文件夹。可是您添加了用户的使用学习成本,用户不是IT专家,将本来应该由开发者完毕的任务转嫁给用户是否合适呢?

要解决问题,关键是要測试,測试Applet在执行时是这么载入这些文件的。经过重复的測试,最终搞清楚当中的来龙去脉:

1.    javax.comm.properties文件能够丢弃,由于通过编程的方法能够在Applet中动态载入串口驱动程序,所以该文件存不存在无所谓。

2.    comm.jar文件是基本的串口訪问类库,能够通过在Applet执行时载入(通过ARCHIVE參数指定,后面有具体的样例),所以也没有必要事先部署到client计算机上。

3.    最关键的是win32comm.dll文件,该文件是用C写的串(并)口驱动程序,Java通过JNI调该文件里的函数来实现对串(并)口的訪问。所以此文件不可或缺。要将该文件部署到client仅仅能通过下载的方式实现,即在Applet执行时检查指定文件夹中是否存在win32comm.dll文件,假设不存在则将server端的win32comm.dll文件下载到client的指定文件夹中,最后再动态装载驱动程序。关于win32comm.dll文件究竟要部署到什么文件夹中,经过測试发现该文件仅仅要存在于由java.library.path系统变量指定的任一文件夹中就可以,该系统变量能够通过System.getProperty(“java.library.path”)方法获取。下面是在我的机器中使用该方法获取的值:

C:/Program Files/Java/jrmc-3.1.2-1.6.0/bin;.;C:/Windows/system32;C:/Windows;C:/Program Files/Java/jrockit-R27.6.5-jre1.6.0_14/bin;C:/Windows/system32;C:/Windows;C:/Windows/System32/Wbem;C:/Windows/System32/WindowsPowerShell/v1.0/;C:/Program Files/ATI Technologies/ATI.ACE/Core-Static;C:/Program Files/Toshiba/Bluetooth Toshiba Stack/sys/;C:/Program Files/SecureCRT/;C:/Program Files/MySQL/MySQL Server 5.1/bin;C:/Tomcat6.0/bin;E:/software/java/jdk/ibm_sdk60/bin;C:/MinGW/bin;C:/Program Files/Java/jrmc-3.1.2-1.6.0/bin;

通过上述分析,我们已经理清了三个文件存放位置,接下来就是怎样详细的实现代码了。

二.代码实现

a)      下载win32comm.dll文件到client:

先看代码的实现:

private static final String LIB_PATH_SUFFIX = "system32";

private static final String DLL_FILE = "win32com.dll";

try {

// 获取载入库时搜索的路径列表

String dirs = System.getProperty("java.library.path");

String[] libs = dirs.split(";");

String libPath = "";

for (String lib : libs) {

if (lib.toLowerCase().endsWith(LIB_PATH_SUFFIX)) {

libPath = lib;

break;

}

}

File dll = new File(libPath, DLL_FILE);

if (!dll.exists()) {

URL url = new URL(super.getCodeBase() + DLL_FILE);

InputStream is = url.openConnection().getInputStream();

FileOutputStream fos = new FileOutputStream(dll);

byte[] buf = new byte[256]; // 读取缓存

int len = 0;

while ((len = is.read(buf)) != -1) {

fos.write(buf, 0, len);

}

fos.flush();

fos.close();

is.close();

System.out.println("创建文件完毕[" + dll + "].");

}

catch (MalformedURLException e) {

e.printStackTrace();

catch (IOException e) {

e.printStackTrace();

}

这段代码的主要算法例如以下:

1.    通过System.getProperty(“java.library.path”)方法获取载入库时搜索的文件夹字符串,每一个文件夹之间是用分号隔开的;

2.    将文件夹字符串按分号拆分成字符串数组,然后取当中的任一一个就可以。只是我喜欢取“C:/Windows/system32”文件夹;

3.    然后实例化一个File对象,该对象存有指向C:/Windows/system32/win32comm.dll文件的句柄。检測该文件是否存在,假设存在则不做不论什么处理,否则进行下载处理;

4.    假设须要下载文件,则先通过getCodeBase()方法获取server端的根URL对象。然后构造一个指向server端win32comm.dll文件的URL对象;

5.    通过URL的openConnection().getInputStream()方法获取InputStream流准备读取;

6.    在client实例化一个FileOutputStream对象,并将输出流写入到client的文件里(C:/Windows/system32/win32comm.dll),完毕文件的下载。事实上文件的下载是通过http协议完毕的,即httpclient。所以server端须要TOMCAT或其它WEBserver软件。

b)      读取条形码

主要实现Applet的3个方法:init、start和destroy方法。先看init方法:

private String driverName = "com.sun.comm.Win32Driver";

public void init() {

try {

System.loadLibrary("win32com");

CommDriver driver = (CommDriver)Class.forName(driverName).newInstance();

driver.initialize();

catch (Exception e) {

System.err.println(e);

}

}

init方法在Applet载入时运行一次且仅一次。所以init方法中适合装载和初始化驱动程序,即载入win32comm.dll文件。

条码扫描设备与调制解调器不同,调制解调器使用“密步”的通信方式,即请求-应答模式。而条码扫描设备是事件驱动的,仅仅有在扫描了条码之后,才干读取串口的数据,所以使用请求-应答模式肯定不行。为了解决问题,Applet必须实现SerialPortEventListener接口,以便在有数据到达时运行特定的方法。另外还须要启动一个线程来等待数据的到达。所以Applet类的签名例如以下:

public class SerialPortApplet extends JApplet implements Runnable,

SerialPortEventListener {

public void run() {

}

public void serialEvent(SerialPortEvent event) {

}

}

当中serialEvent(SerialPortEvent event)方法就是须要实现的接口方法,当串口有数据到达时,则会运行该方法中的代码。

start方法在init方法运行完成之后运行,在Applet的整个生命周期中,start方法能够被运行多次。所以start方法能够用来实现寻找可用port,打开port,设置port參数,等待数据到达以及数据处理等代码,代码例如以下所看到的:

private CommPortIdentifier portId;

private StringBuilder barcode = new StringBuilder();

private InputStream is;

private boolean over = false; //退出线程的标志

private SerialPort serialPort;

static {

    System.setSecurityManager(null); //禁用安全管理器(必须写)

}

public void start() {

Enumeration ports = CommPortIdentifier.getPortIdentifiers();

while (ports.hasMoreElements()) {

portId = (CommPortIdentifier) ports.nextElement();

if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { // 是串口

if (portId.getName().equals("COM1")) {

break;

}

}

}

try {

serialPort = (SerialPort) portId.open("App1",2000); // 打开port

is = serialPort.getInputStream();

serialPort.addEventListener(this); // 注冊监听器

serialPort.notifyOnDataAvailable(true); // 数据达到时发出通知

serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // 设置port參数

catch (PortInUseException e) {

System.err.println(e);

catch (IOException e) {

System.err.println(e);

catch (TooManyListenersException e) {

System.err.println(e);

catch (UnsupportedCommOperationException e) {

System.err.println(e);

}

// 启动线程

Thread t = new Thread(this);

t.start();

try {

t.join();// 等待线程结束

catch (InterruptedException e) {

}

System.out.println("barcode[" + barcode + "]");

}

线程接口的实现和监听器接口的实现代码例如以下所看到的:

public void run() {

while (!over) {

}

try {

if (is != null) {

is.close();

}

if (serialPort != null) {

serialPort.close();

}

catch (IOException e) {

System.out.println(e);

}

}

public void serialEvent(SerialPortEvent event) {

switch (event.getEventType()) {

case SerialPortEvent.DATA_AVAILABLE: //数据到达时运行

try {

while (true) {

int b = is.read(); // 假设读取不到数据则会堵塞

if (b == 10 || b == 13) { // 假设读到回车或换行则表示读取完毕

over = true;

break;

else {

barcode.append(new String(new byte[] { (byte) b }));

}

}

catch (IOException e) {

System.err.println(e);

}

}

}

destroy方法在Applet销毁时运行且运行一次,所以能够该方法中编写资源释放的代码,代码实现例如以下:

public void destroy() {

try {

if (is != null) {

is.close();

}

if (serialPort != null) {

serialPort.close();

}

catch (IOException e) {

System.out.println(e);

}

}

c)      HTML页面(index.html)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />

<title></title>

</head>

<body>

<!--"CONVERTED_APPLET"-->

<!-- HTML CONVERTER -->

<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"

WIDTH = "250" HEIGHT = "140"  codebase="http://java.sun.com/update/1.6.0/jinstall-6u17-windows-i586.cab#Version=6,0,0,4">

<PARAM NAME = CODE VALUE = "org.oakman.applets.SerialPortApplet.class" >

<PARAM NAME = CODEBASE VALUE = "." >

<PARAM NAME = ARCHIVE VALUE = "comm.jar, serial_port.jar" >

<PARAM NAME="type" VALUE="application/x-java-applet;version=1.6">

<PARAM NAME="scriptable" VALUE="false">

<COMMENT>

<EMBED type="application/x-java-applet;version=1.6"  CODE = "org.oakman.applets.SerialPortApplet.class" CODEBASE = "." ARCHIVE = " comm.jar,serial_port.jar" WIDTH = "250" HEIGHT = "140"  scriptable=false pluginspage="http://java.sun.com/products/plugin/index.html#download"><NOEMBED>

</NOEMBED>

</EMBED>

</COMMENT>

</OBJECT>

<!--"END_CONVERTED_APPLET"-->

</body>

</html>

当中比較重要的是ARCHIVE參数,能够将Applet须要用到的全部jar类库都在这个參数中进行设置,多个jar文件之间用逗号进行分隔。假设client没有安装JRE,则首先会要求用户下载JRE,正常情况下,下载JRE须要10分钟左右的时间。

经过上述步骤,我们完毕了全部须要实现的代码。将全部Java代码打包成jar文件,然后和html文件一起部署到TOMCAT6中,启动,一切正常,然后很高兴的打开浏览器,输入url,双眼充满期望的等待令人兴奋的一幕。只是……,报错了!很的沮丧!错误提示没有訪问权限!!郁闷中……

三.部署

Java号称是最安全的,所以Applet作为在网络上能够随意传播的小应用程序当然更加须要安全。所以在默认情况下Applet仅仅能执行在JVM的沙箱中。不能訪问client的不论什么资源,包含文件系统的读写,网络套接字等。所以出现上述错误理所当然,反而证明了Java的确很的安全。

为了走出沙箱,我们必须对Applet进行签名:

1.    创建密钥:

使用例如以下命令进行密钥的创建,这里使用RSA算法而不是Java默认的DSA算法

keytool -genkey -alias oakman -keyalg RSA

执行时会要求您输入密钥库的口令,并要求您输入名字,组织和位置等信息。填好后就会产生密钥(密钥文件在用户文件夹中,找.keystore文件)。

2.    从CA订购签名证书:

为了从CA订购签名证书,你须要从密钥库中导出证书签名申请(CSR文件)。使用例如以下命令

keytool -certreq -alias oakman -file oakman.csr

该命令会在当前文件夹中产生一个oakman.csr文件,然后你能够用这个文件以及证明你身份的证明或证件以及数K的RMB到CA那里申请你的证书(比較常见的CA有Verisign)。假设申请成功,CA会给你一个BASE64编码证书,你就能够把它导入到密钥库中给自己编写的Applet进行签名了,导入命令例如以下:

keytool -import -alias oakman -file oakman.cer

当中oakman.cer就是CA给你的证书。

3.    对Applet的jar文件进行签名:

已经将CA的证书导入到密钥库中,那么就能够对自己编写的Applet进行签名了(当然,先要打包成JAR包),使用例如以下命令:

jarsigner serial_port.jar oakman

jarsigner comm.jar oakman

Applet全部用到的jar文件都要进行签名。

经过上述步骤,我们的Applet就能够走出沙箱了,能够訪问client的不论什么资源,包含文件系统,外设以及网络套接字等。将条形码扫码枪接上我笔记本的串口,找了一本书,对着书上的条码一扫,哔!!扫描成功,接着在Java控制台出现一串数字,OK!最终搞定。(注:因为我笔记本没有串口,所以通过USB转串口来模拟出串口,可能是因为驱动程序的原因,假设在没有关闭串口的情况关闭IE浏览器,则操作系统必定死机,仅仅能手动重新启动操作系统。)

当然,作为測试,我们没有必要花数K的RMB去CA那里申请证书,所以能够将步骤2省略。在生成密钥库之后直接对JAR文件进行签名。

四.部署文件夹

下面为我机器上TOMCAT中应用程序的部署文件夹:

pay

|-- WEB-INF

|-- web.xml

|-- comm.jar

|-- serial_port.jar

|-- index.html

时间: 2024-11-04 21:42:30

web应用程序访问串口的相关文章

[转] ASP.NET WEB API程序在VS启动或发布到IIS后启动后发生 - Could not load file or assembly &#39;System.Web.Http.WebHost’异常,无法正常访问

Just do Copy Local = true in the properties for the assembly(System.Web.Http.WebHost) and then do a redeploy, it should work fine. http://stackoverflow.com/questions/20323107/could-not-load-file-or-assembly-system-web-http-webhost-after-published-to-

Web 应用程序项目 XXXX 已配置为使用 IIS。 无法访问 IIS 元数据库。您没有足够的特权访问计算机上的 IIS 网站。(转载)

Web 应用程序项目 XXXX 已配置为使用 IIS. 无法访问 IIS 元数据库.您没有足够的特权访问计算机上的 IIS 网站. 2012年05月19日 ⁄ 综合 ⁄ 共 261字 ⁄ 字号 小 中 大 ⁄ 评论关闭 问题:Windows8下直接使用VS 打开项目,出现问题: XXXX 已配置为使用 IIS.  无法访问 IIS 元数据库.您没有足够的特权访问计算机上的 IIS 网站. 解决: 1.以"管理员权限"运行VS,在VS菜单打开项目即可. 但是以上解决方法不方便. 2.较为

您试图在此 Web 服务器上访问的 Web 应用程序当前不可用

错误提示: 服务器应用程序不可用 您试图在此 Web 服务器上访问的 Web 应用程序当前不可用.请点击 Web 浏览器中的“刷新”按钮重试您的请求. 管理员注意事项: 详述此特定请求失败原因的错误信息可在 Web 服务器的系统事件日志中找到.请检查此日志项以查明导致该错误发生的原因. 原因: 先装了.net,而后装了iis,用户的权限没加进去引起的 解决方案: 只要在.net下 Microsoft visual 2005->visual studio tools->visual studio

Web应用程序项目XXXX已配置为使用IIS。无法访问IIS元数据库。您没有足够的特权访问计算机上的IIS网站

问题:Windows8下直接使用VS打开项目,出现问题:XXXX已配置为使用IIS.无法访问IIS元数据库.您没有足够的特权访问计算机上的IIS网站.解决:1.以“管理员权限”运行VS,在VS菜单打开项目即可.但是以上解决方法不方便.2.较为完美的解决方案:(1)右键点击XXXX项目,选择编辑XXXX.csprj.打开该项目的项目文件(2)在打开的项目文件中搜索<UseIIS>找到Web应用程序的属性设置段(3)将UseIIS段的值由True改成False,关闭项目文件(4)重新加载XXXX项

Windows azure Web 应用程序代理服务器&mdash;ADFS的extranet访问权限

Windows azure Web 应用程序代理服务器-ADFS的extranet访问权限 我们之前介绍了,在windows azure下配置联合身份验证服务,实现通过本地的Active Direcroty用户验证范根windows azure Active Direcroty服务,默认操作后,只有在同一个内部网络才能访问,那我们如果要外部访问的话,我们需要怎么做呢,当然按照常理我们需要将ADFS的相应的端口对外发布即可,比如80.443等.但是在官网的方法是我们需要单独部署一台proxy服务,

Web 应用程序项目 Himall.Web 已配置为使用 IIS。 无法访问 IIS 元数据库

Web应用程序项目XXXX已配置为使用IIS.无法访问IIS元数据库.您没有足够的特权访问计算机上的IIS网站,xxxxiis 问题:Windows8下直接使用VS打开项目,出现问题:XXXX已配置为使用IIS.无法访问IIS元数据库.您没有足够的特权访问计算机上的IIS网站.解决:1.以"管理员权限"运行VS,在VS菜单打开项目即可.但是以上解决方法不方便.2.较为完美的解决方案:(1)右键点击XXXX项目,选择编辑XXXX.csprj.打开该项目的项目文件(2)在打开的项目文件中搜

Atitit.提升软件Web应用程序 app性能的方法原理 h5 js java c# php python android .net

1. 提升单例有能力的1 2. 减少工作数量2 2.1. 减少距离2 2.2. 添加索引2 2.3. Dma api2 2.4. Cdn2 2.5. Cache2 2.6. Pool技术2 2.7. 减少HTTP请求数2 2.8.  ·更大的数据格式2 2.9. 循环展开2 2.10. 循环转置3 2.11. 提高Cache命中率3 2.12. 小组件替换大组件4 3. 并行处理4 3.1. 多线程4 3.2. 数据库分区4 4. 减少等候4 4.1.  2.流水线(Pipeline)4 4.2

对 Web 应用程序进行性能调优

动态的 Web 应用程序能够存储大量信息,让用户能够通过熟悉的界面立即访问这些信息.但是,随着应用程序越来越受欢迎,可能会发现对请求的响应速度没有以前那么快了.开发人员应该了解 Web 应用程序处理 Web 请求的方式,知道在 Web 应用程序开发中可以做什么,不能做什么,这有助于减少日后的麻烦. 静态的 Web 请求(比如图 1 所示的请求)很容易理解.客户机连接服务器(通常通过 TCP 端口 80),使用 HTTP 协议发出一个简单的请求. 图 1. 客户机通过 HTTP 请求静态的文件 服

ASP.NET MVC Web API 学习笔记---第一个Web API程序

http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html 1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过在浏览器中使用 JavaScript来创建更丰富的HTML体验.所以我相信Web API会越来越有它的用武之地. 说道Web API很多人都会想到Web服务,但是他们仍然有