使用 POSIX 消息队列运行 JNA 示例

Posted

技术标签:

【中文标题】使用 POSIX 消息队列运行 JNA 示例【英文标题】:Running a JNA example with POSIX message queues 【发布时间】:2012-08-09 08:02:52 【问题描述】:

我需要通过 POSIX 消息队列与 Java 应用程序和 C 进程通信,我想使用 JNA 来完成。

经过一些研究、阅读和您的帮助,我从一个尝试创建消息队列的简单 Java 应用程序开始。

/** Simple example of JNA interface mapping and usage. */
public class HelloJNAWorld 

    // This is the standard, stable way of mapping, which supports extensive
    // customization and mapping of Java to native types.

     public interface IPCLibrary extends Library 
        IPCLibrary INSTANCE = (IPCLibrary)
                Native.loadLibrary("c",IPCLibrary.class);


        int msgget(NativeLong key, int msgflg);

    

    public static void main(String[] args) 

        int id = IPCLibrary.INSTANCE.msgget(new NativeLong(12500), 0600|1);


        if(id<0)
                System.out.println("Error creating message queue. Id:"+id);
                System.out.println(Native.getLastError());
        else
                System.out.println("Message queue id:" + idCola);
        

    

我认为msgctl 是最简单的映射方法,因为它只是int msgget(key_t key, int msgflag);。我假设我可以将key_t 映射为NativeLong,但msget 返回-1。所以我检查了lastError,返回的值为2,这意味着“没有这样的文件或 目录”根据errno代码。

你能帮我解决这个问题吗?也许key_t 应该以另一种方式映射?也许我需要更多的库或类似的东西?

【问题讨论】:

我想我找到了一些东西。我没有注意到错误代码 2 以通用方式表示“没有这样的文件或目录”这一事实。但是,应用于“msgget”错误列表意味着“不存在 key 的消息队列并且 msgflg 没有断言 IPC_CREAT”。所以我查找了 IPC_CREAT 的值并更改了“int id = IPCLibrary.INSTANCE.msgget(new NativeLong(12500), 0600|1);”对于另一个“int id = IPCLibrary.INSTANCE.msgget(new NativeLong(12500), 0600|01000);”。现在 msgget 返回 0,这似乎不太好,但我正在寻找答案。 【参考方案1】:

由于没有人回答这个问题,而且有些人可能需要我当时需要的帮助,所以我在这里发布了我的测试类代码。 :-)

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Platform;
import com.sun.jna.Structure;

/** Simple example of JNA interface mapping and usage. */
public class HelloJNAWorld 

    // This is the standard, stable way of mapping, which supports extensive
    // customization and mapping of Java to native types.

    public interface CLibrary extends Library 
        CLibrary INSTANCE = (CLibrary)
        Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),CLibrary.class);


        void printf(String format, Object... args);


    

    public interface IPCLibrary extends Library 
        IPCLibrary INSTANCE = (IPCLibrary)           
        Native.loadLibrary("c",IPCLibrary.class);



        class WaitQueue extends Structure

        


        // mapping msqid_ds structure
        class MsqidDs extends Structure
            long msg_stime;       /* last msgsnd time */
            long msg_rtime;       /* last msgrcv time */
            long msg_ctime;       /* last change time */
            short msg_cbytes;
            short msg_qnum;
            short msg_qbytes;      /* max number of bytes on queue */
            short msg_lspid;       /* pid of last msgsnd */
            short msg_lrpid;       /* last receive pid */
        

        // END mapping msqid_ds structure

        class MsgBuf extends Structure
            NativeLong mtype; /* type of message */
            byte mtext[] = new byte[1];
        


        class MyMsgBuf extends MsgBuf
            public NativeLong messageKind;
            public byte[] contenido = new byte[1024];
        

        // Initialize queue, or if it exists, get it            
        int msgget(NativeLong key, int msgflg);
        // Send messages to queue
        // int msgsnd(int msqid, struct msgbuf *ptrkey, int length, int flag);
        int msgsnd(int msqid, MsgBuf ptrkey, int msgsz, int msgflg);
        // Receive messages from queue
        // int msgrcv(int msqid, struct msgbuf *ptrkey, int length, long msgtype, int flag);
        int msgrcv(int msqid, MsgBuf ptrkey, int length, long msgtype, int flag);            

    

    public static void main(String[] args) 

        int idCola = IPCLibrary.INSTANCE.msgget(new NativeLong(12500), 0);            

        if(idCola<0)
            System.out.println("The queue can't be created. IdCola:"+idCola);           
            System.out.println("Error msgget: " + Native.getLastError());
        else
            System.out.println("Queue with id:" + idCola + "has been recovered");           
            // Send message
            IPCLibrary.MyMsgBuf mensaje = new IPCLibrary.MyMsgBuf();
            mensaje.tipoMensaje = new NativeLong(1);
            mensaje.contenido = "Sending message".getBytes();
            int devSend = IPCLibrary.INSTANCE.msgsnd(idCola, mensaje, mensaje.contenido.length, 1);
            if(devSend != 0)
                System.out.println("Send response: "+devSend);
                System.out.println("Error value: " + Native.getLastError());
            
        

        // Receiving message
        IPCLibrary.MyMsgBuf mensajeRecibido =  new IPCLibrary.MyMsgBuf();        
        int bytesRecibidos = IPCLibrary.INSTANCE.msgrcv(idCola, mensajeRecibido, mensajeRecibido.contenido.length, 1234, 0);
        if(bytesRecibidos > 0)
            System.out.println("C message has been received: " + new String(mensajeRecibido.contenido));
        else
            System.out.println("msgrcv error: " + Native.getLastError());
        


        // Send closing message
        IPCLibrary.MyMsgBuf mensajeCierre = new IPCLibrary.MyMsgBuf();
        mensajeCierre.tipoMensaje = new NativeLong(2);
        mensajeCierre.contenido = "Closing queue".getBytes();
        int devSend = IPCLibrary.INSTANCE.msgsnd(idCola, mensajeCierre, mensajeCierre.contenido.length, 1);
        if(devSend != 0)
            System.out.println("Send response: "+devSend);
            System.out.println("Error value: " + Native.getLastError());
                    

    

我真的希望这可以帮助别人。

【讨论】:

【参考方案2】:

我清理了你的代码并让它运行起来。 你需要两个任务。一发一收。 只需将上一篇文章中的 main() 替换为下面的 main()。它对我有用。感谢您发布您的努力让我开始。 另请参阅 kirk.c 和 spock.c 以获得良好的 c 示例http://beej.us/guide/bgipc/output/html/multipage/mq.html

   public static void main(String[] args) 
   double SLEEP_MINUTES = 0.1;
   int IPC_CREAT = 01000;  // starts with 0 so its octal or 512 
   int IPC_EXCL  = 02000;
   int IPC_NOWAIT  = 04000;
   int MSG_EXCEPT = 020000;
   int MSG_NOERROR =  010000;  // truncate the message if its to big     
   int msgflg_msgrcv = MSG_NOERROR; //  truncate the message if its to big
   int msgflg_msgget = 0666 | IPC_CREAT;
   int msgflg_msgsnd = 0;
   int msgtype_msgrcv = 0; // read them all
   NativeLong msgtype_msgsnd = new NativeLong(1); // just needs to be a positive number
   NativeLong msgkey = new NativeLong(12500);  



    int msqid = IPCLibrary.INSTANCE.msgget(msgkey, msgflg_msgget);            

    if(msqid<0)
    
        System.out.println("The queue can't be created. msqid:"+msqid);           
        System.out.println("Error msgget: " + Native.getLastError());
        System.exit(0);
    

    System.out.println("Queue with id:" + msqid + "has been found or created");  
    for(int i=0;i<100;i++)
    
        // Send message
        IPCLibrary.MyMsgBuf message = new IPCLibrary.MyMsgBuf();
        message.messagetype = msgtype_msgsnd;
        message.content = ("Sending message"+i+'\0').getBytes();           // add 1 for the '\0'
        int devSend = IPCLibrary.INSTANCE.msgsnd(msqid, message, message.content.length+1,
                msgflg_msgsnd);
        if(devSend != 0)
        
            System.out.println("Send response: "+devSend);
            System.out.println("Error value: " + Native.getLastError());
            System.exit(0);
        
        System.out.println("Sent "+i);            
        try
        
            Thread.sleep((long)(SLEEP_MINUTES*60.0*1000.0)); 
        
        catch (InterruptedException e) 
        
            System.out.println("InterruptedException while writing");
            System.out.println(e.getMessage());                 
        

    




     public static void main(String[] args) 
// found these in /usr/include/bits/*.h
int IPC_CREAT = 01000;  // remember if it starts with a '0' its octal or 512 
int IPC_EXCL  = 02000;
int IPC_NOWAIT  = 04000;
int MSG_EXCEPT = 020000;
int MSG_NOERROR =  010000;  // truncate the message if its to big     

int msgflg_msgrcv = MSG_NOERROR; //  truncate the message if its to big
int msgflg_msgget = 0666 | IPC_CREAT; // create the queue if its not there , let everybody read and write
int msgtype_msgrcv = 0; // read them all
NativeLong msgtype_msgsnd = new NativeLong(1); // just needs to be a positive number
NativeLong msgkey = new NativeLong(12500);  

    int msqid = IPCLibrary.INSTANCE.msgget(msgkey, msgflg_msgget);            
    if(msqid<0)
    
        System.out.println("The queue can't be created. msqid:"+msqid);           
        System.out.println("Error msgget: " + Native.getLastError());
        System.exit(0);
    

    System.out.println("Queue with id:" + msqid + "has been found or was created");  
    for(int i=0;i<100;i++)
    
        IPCLibrary.MyMsgBuf message =  new IPCLibrary.MyMsgBuf();        
        int ret = IPCLibrary.INSTANCE.msgrcv(msqid, message, message.content.length,
                msgtype_msgrcv,msgflg_msgrcv);
        if(ret > 0)
        
            System.out.println("message has been received: " + ret);
            System.out.println(new String(message.content));
        
        else
        
            System.out.println("msgrcv error: " + Native.getLastError());
        
    

   
 

【讨论】:

以上是关于使用 POSIX 消息队列运行 JNA 示例的主要内容,如果未能解决你的问题,请参考以下文章

是否可以确定 POSIX 消息队列中有多少条消息?

Posix消息队列

尝试使用 POSIX 消息队列创建消息队列时权限被拒绝

POSIX 消息队列 - 打开时出错:参数无效

Posix消息队列

Posix消息队列