24

我正在尝试使用带有以下代码的 javax.smartcardio API 加载智能卡终端:

public CardTerminal getReadyCardTerminal() throws CardException {

    TerminalFactory factory = TerminalFactory.getDefault();
    CardTerminals terminals = factory.terminals();
    List<CardTerminal> list = terminals.list(State.CARD_PRESENT);

    while (list.isEmpty()) {
        terminals.waitForChange(1000);
        list = terminals.list(State.CARD_PRESENT);
    }
    CardTerminal cardTerminal = list.get(0);
    return cardTerminal;
}

...而且我总是遇到以下异常:

java.lang.IllegalStateException: no terminals
at javax.smartcardio.TerminalFactory$NoneCardTerminals.waitForChange(TerminalFactory.java:145)

在 Windows Vista/7 上一切正常,但我无法让它在 Linux 上运行。我正在使用 Ubuntu 12.04 64 位。

我使用以下命令安装了 pcscd 服务:

sudo apt-get install libccid pcscd libpcsclite-dev libpcsclite1
sudo service pcscd start

pcsc_scan 命令会打印:

PC/SC device scanner
V 1.4.18 (c) 2001-2011, Ludovic Rousseau <ludovic.rousseau@free.fr>
Compiled with PC/SC lite version: 1.7.4
Using reader plug'n play mechanism
Scanning present readers...
0: OMNIKEY CardMan 3x21 00 00

Tue Sep 11 15:44:49 2012
Reader 0: OMNIKEY CardMan 3x21 00 00
  Card state: Card inserted, 
  ATR: <some hexa codes>
  ...

所以一切看起来都很好,但是智能心脏不起作用。我正在尝试使用 Oracle 和 OpenJDK 1.7.0_05、32 和 64 位。

该代码在 Ubuntu 32 位环境中使用 OpenJDK 运行正常(但不是使用 Oracle JDK,不知道为什么)。所以我认为这是从 Java 到 PC/SC 库的 64 位桥的问题。

有任何想法吗?

谢谢。

4

7 回答 7

38

我想我找到了解决方法,因为我遇到了类似的问题。在来自 ubuntu的错误报告中,它说 javax.smartcardio 库在错误的目录中搜索 PC/SC 库。

通过在我的机器上指定 PC/SC 库的路径,就像 bugreport 提到的那样,我让它工作了。

错误报告中的路径对我来说是错误的,我使用的是 64 位 Fedora,其中 pc/sc 库安装在 /usr/lib64/libpcsclite.so.1

所以我的解决方法是像这样指定java的库路径:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1

根据您的 Linux 发行版,libpcsclite.so.1实际位置可能会有所不同,也可能位于/lib/x86_64-linux-gnu/libpcsclite.so.1(即 Kubuntu 15.04)。在这种情况下,这样称呼它:

java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1
于 2012-09-12T10:55:55.427 回答
8

我正在使用带有 debian arm 版本的树莓派

首先找到 libpcsclite 的位置:

$ ldd -r /usr/bin/pcsc_scan

然后使用 libpcsclite 位置:

java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1
于 2013-12-30T03:53:43.453 回答
4

对于使用 64 位机器在 Ubuntu 14 上苦苦挣扎的其他人。我发现.so文件实际上位于以下目录中

/usr/lib/x86_64-linux-gnu/libpcsclite.so

因此,使用以下设置运行我的应用程序对我有用

-Dsun.security.smartcardio.library=/usr/lib/x86_64-linux-gnu/libpcsclite.so

于 2015-03-03T12:28:39.570 回答
4

调用程序时需要提供 libpcsclite.so.1 的路径,如下所示

java -Dsun.security.smartcardio.library=/path/to/libpcsclite.so.1

如果您不知道库的路径,请使用以下命令

find /usr/lib -name libpcsclite.so.1

这通常会显示您机器上的路径。我在 Ubuntu 10(32 位)和 Ubuntu 15(32 位和 64 位)上都使用了它

如果你像我一样懒惰,你可以在你的程序中包含这部分代码,然后再使用 javax.smartcardio 库

      try {
            String comm[] = { "find", "/usr", "/lib", "-name",
                    "libpcsclite.so.1" };
            Process p = Runtime.getRuntime().exec(comm);

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(p.getInputStream()));

            while ((line = reader.readLine()) != null && !line.equals("")) {
                if (line.contains("libpcsclite.so.1")) {
                System.setProperty("sun.security.smartcardio.library",line);
                    break;
                }

            }
            p.waitFor();

        } catch (Exception e) {

            e.printStackTrace();
        }

现在您可以像往常一样运行您的代码,而无需包含 libpcsclite.so.1 的路径

于 2016-06-14T05:24:50.807 回答
2

除了提供路径作为参数的解决方案,如下所示:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1

如果您不想在每次调用 JVM 时都提供此信息,请将其设置在环境变量 _JAVA_OPTIONS 和/或 JAVA_OPTS 中:

export _JAVA_OPTIONS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1"
export JAVA_OPTS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1"

由于这是影响整个系统的错误的解决方法,因此恕我直言,在系统范围内应用此解决方法也是有意义的。

JAVA_OPTS 具有本地范围,必须由运行代码的脚本进行评估;_JAVA_OPTIONS 应该由 JRE 自动评估。

于 2015-07-10T12:47:45.103 回答
1

另一种方法(我最喜欢的)是创建一些符号链接。

它的优点是可以在系统范围内工作(没有 jvm 参数,没有环境变量)。

对于我(心爱的)debian jessie amd64:

ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so libpcsclite.so
ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1 libpcsclite.so.1
ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0 libpcsclite.so.1.0.0

注意:这可能需要超级用户访问权限。

于 2015-09-24T19:24:13.850 回答
1

补充@AshanPerera的答案,因为有时每次搜索可能会很慢,您可以在第一次搜索它,并将位置存储在一个文件中,然后从那时起读取它:

        try {

        String filename = "libpcsclite.location"; 
        File propertyFile = new File(filename);
        if(propertyFile.createNewFile()) 
        {   
            String commandWithArguments[] = { "find", "/usr", "/lib", "-name","libpcsclite.so.1" };
            Process searchProcess = Runtime.getRuntime().exec(commandWithArguments);
            BufferedReader searchReader = new BufferedReader(new InputStreamReader(searchProcess.getInputStream()));
            String propertyValue;
            while ( (propertyValue = searchReader.readLine()) != null && !propertyValue.equals("")) 
            {
                if (propertyValue.contains("libpcsclite.so.1")) {
                    BufferedWriter propertyWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(propertyFile)));
                    propertyWriter.write(propertyValue);
                    propertyWriter.close();
                    System.setProperty("sun.security.smartcardio.library",propertyValue);
                    break;
                }
            }
            searchProcess.waitFor();
        }
        else 
        {  
            BufferedReader propertyReader = new BufferedReader(new InputStreamReader(new FileInputStream(propertyFile)));                 
            String propertyValue = propertyReader.readLine(); 
            System.setProperty("sun.security.smartcardio.library",propertyValue);       
        }
    } catch (Exception e) {

        e.printStackTrace();
    }
于 2018-10-15T20:52:56.717 回答