I need to communicate a Java application and a C process via POSIX message queue, and I would like to do it using JNA.
After some research, reading and your help, I started with a simple Java application which tries to create a message queue.
/** 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);
}
}
}
I thought msgctl was the simplest method to map because it's just int msgget(key_t key, int msgflag);. I have assumed that I could map key_t as a NativeLong but msget is returning -1. So I've checked lastError and the value returned is 2, which means "No such file or
directory" according to errno codes.
Could you help me with this? Maybe key_t should be mapped in another way? Maybe I need more libraries or something like that?
Since no one answer this question, and some could need the help I needed those days, I'm posting my test class code here. :-)
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());
}
}
}
I really hope this can help someone else.
I cleaned up your code and got it running.
You need two tasks . one to send and one to receive.
just replace the main() in your previous post with the main()'s below. It worked for me. Thanks for posting your efforts for me to start with.
Also see kirk.c and spock.c for a good c example 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());
}
}
}
}
Related
I use jna to run WMI queries.
The following code queries WMI SELECT Caption,Capabilities from Win32_DiskDrive. The Type of Win32_DiskDrive.Capabilities is uint16[] and result.getValue returns a SAFEARRAY Instance.
System.out.println("Var Type(3 expected): " + value.getVarType().intValue());
returns randomly 0 or 3 if I start the process several times.
System.out.println("Size (>0 expected): " + (value.getUBound(0) - value.getLBound(0)));
is correct, but
Object el = value.getElement(0);
fails.
value.accessData();
returns null which is unexpected as well, so I cannot use OaIdlUtil#toPrimitiveArray (Nullpointer)
Unfortunately, the code does not work, and I have no idea what might be wrong. Any Ideas?
enum Win32_DiskDrive_Values {
Caption,
Capabilities
}
public static void main(String[] args) throws IOException, InterruptedException {
try {
WmiQuery<Win32_DiskDrive_Values> serialNumberQuery = new WmiQuery<Win32_DiskDrive_Values>("Win32_DiskDrive", Win32_DiskDrive_Values.class);
Ole32.INSTANCE.CoInitializeEx(null, Ole32.COINIT_MULTITHREADED);
WmiResult<Win32_DiskDrive_Values> result = serialNumberQuery.execute();
for (int i = 0; i < result.getResultCount(); i++) {
System.out.println(result.getValue(Win32_DiskDrive_Values.Caption, i));
SAFEARRAY value = (SAFEARRAY) result.getValue(Win32_DiskDrive_Values.Capabilities, i);
// According to https://learn.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-diskdrive, the type of Capabilities
// should be uint16[] which should be Variant.VT_I2 (2-byte integer)
// however, it is not constant. sometimes it is 0, sometimes Variant.VT_I2 (3);
System.out.println("Var Type(3 expected): " + value.getVarType().intValue());
System.out.println("Size (>0 expected): " + (value.getUBound(0) - value.getLBound(0)));
Object el = value.getElement(0);
System.out.println("Element 0 (!=null expected): " + el);
Pointer pointer = value.accessData();
System.out.println("pointer (!=null expected): " + pointer);
}
} catch (Throwable e) {
e.printStackTrace();
} finally {
Ole32.INSTANCE.CoUninitialize();
}
}
The WMI code that I submitted to the JNA project is only set up to handle primitive values and Strings, not arrays. The problem you are encountering is that WMI is returning the pointer address to the array (either an empty array with VT_EMPTY = 0, or a 32-bit poniter with VT_I4 = 3). But the WMI result is released after the iteration, so you cannot use the WmiResult to fetch the object.
You need to write your own code (using the JNA implementation as a starting point) to grab the SAFEARRAY during iteration. You asked this question on the JNA website and #matthiasblaesing posted the following snippet which works for your use case:
public static void main(String[] args) throws IOException, InterruptedException {
Ole32.INSTANCE.CoInitializeEx(null, Ole32.COINIT_MULTITHREADED);
// Connect to the server
Wbemcli.IWbemServices svc = WbemcliUtil.connectServer("ROOT\\CIMV2");
// Send query
try {
Wbemcli.IEnumWbemClassObject enumerator = svc.ExecQuery("WQL", "SELECT Caption, Capabilities, CapabilityDescriptions FROM Win32_DiskDrive",
Wbemcli.WBEM_FLAG_FORWARD_ONLY | Wbemcli.WBEM_FLAG_RETURN_IMMEDIATELY, null);
try {
IWbemClassObject[] result;
VARIANT.ByReference pVal = new VARIANT.ByReference();
IntByReference pType = new IntByReference();
IntByReference plFlavor = new IntByReference();
while(true) {
result = enumerator.Next(0, 1);
if(result.length == 0) {
break;
}
COMUtils.checkRC(result[0].Get("Caption", 0, pVal, pType, plFlavor));
System.out.println("---------" + pVal.getValue() + "-------------");
OleAuto.INSTANCE.VariantClear(pVal);
COMUtils.checkRC(result[0].Get("CapabilityDescriptions", 0, pVal, pType, plFlavor));
SAFEARRAY safeArray = (SAFEARRAY) pVal.getValue();
for(int i = safeArray.getLBound(0); i<=safeArray.getUBound(0); i++) {
System.out.println("\t" + safeArray.getElement(i));
}
OleAuto.INSTANCE.VariantClear(pVal);
COMUtils.checkRC(result[0].Get("Capabilities", 0, pVal, pType, plFlavor));
safeArray = (SAFEARRAY) pVal.getValue();
for(int i = safeArray.getLBound(0); i<=safeArray.getUBound(0); i++) {
System.out.println("\t" + safeArray.getElement(i));
}
OleAuto.INSTANCE.VariantClear(pVal);
result[0].Release();
}
} finally {
// Cleanup
enumerator.Release();
}
} finally {
// Cleanup
svc.Release();
}
Ole32.INSTANCE.CoUninitialize();
}
// CLIENT SOURCE
while(!isStop){
try{
Object ob = mc.getOis().readObject();
try{
message = (String) ob;
} catch (ClassCastException e){
try {
user = (User) ob;
mc.user = (User) ob;
message = "none";
} catch ( ClassCastException ee ) {
Room room = (Room) ob;
mc.setRoom(room);
System.out.println("room come in");
for (int i = 0; i<mc.room.userlist.size(); i++ )
{
System.out.println("ThreadUserNum:" + room.userlist.get(i).getPlayer_Num());
}
mc.roomidimg();
message = "none";
}
}
}
}
// SERVER SOURCE
public void roombroodcast ( Room msg, int room_id) throws IOException{
if (room_id == 1){
for( ServerThread ct : sv.getroom1list() ){
for( int i = 0; i<msg.getUserlist().size(); i++){
System.out.println(i + "broodcast:" + msg.getUserlist().get(i).getUser_Id());
}
ct.send( msg );
}
} else {
for( ServerThread ct : sv.getroom2list() ){
ct.send( msg );
}
}
}
We are making a game but we have some problems.
The first user, who entered the game first, cannot get the other user's room
class broadcasting.
I mean, the other user or another user can get the room class broadcasting but the first one cannot get the updated room information.
How can I update the room class broadcasting problem?
We are using sockets to communicate.
You are always sending the same object, so serialization will not actually re-send it: it economizes, as described in the Object Serialization Specification. So updating it and sending it again will not affect the object received at the receiver.
You need to investigate ObjectOutputStream.reset() or ObjectOutputStream.writeUnshared().
I want to take real-time data using modbus tcp/ip simulator for filling of a tank that uses port no 502.
How can I write a code in java to get the holding register value from the simulator and also I want to control the values of it?
If you use a Modbus library like this one most of the work is already done for you.
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder("localhost").build();
ModbusTcpMaster master = new ModbusTcpMaster(config);
CompletableFuture<ReadHoldingRegistersResponse> future =
master.sendRequest(new ReadHoldingRegistersRequest(0, 10), 0);
future.thenAccept(response -> {
System.out.println("Response: " + ByteBufUtil.hexDump(response.getRegisters()));
ReferenceCountUtil.release(response);
});
import java.io.* ;
import java.net.* ;
import java.util.*;
public class Modcli {
public static void main(String argv[]) {
if (argv.length < 4) {
System.out.println("usage: java test3 dns_name unit reg_no num_regs");
System.out.println("eg java test3 aswales8.modicon.com 5 0 10");
return;
}
try {
String ip_adrs = argv[0];
int unit = Integer.parseInt(argv[1]);
int reg_no = Integer.parseInt(argv[2]);
int num_regs = Integer.parseInt(argv[3]);
System.out.println("ip_adrs = "+ip_adrs+" unit = "+unit+" reg_no = "+
reg_no+" num_regs = "+num_regs);
// set up socket
Socket es = new Socket(ip_adrs,502);
OutputStream os= es.getOutputStream();
FilterInputStream is = new BufferedInputStream(es.getInputStream());
byte obuf[] = new byte[261];
byte ibuf[] = new byte[261];
int c = 0;
int i;
// build request of form 0 0 0 0 0 6 ui 3 rr rr nn nn
for (i=0;i<5;i++) obuf[i] = 0;
obuf[5] = 6;
obuf[6] = (byte)unit;
obuf[7] = 3;
obuf[8] = (byte)(reg_no >> 8);
obuf[9] = (byte)(reg_no & 0xff);
obuf[10] = (byte)(num_regs >> 8);
obuf[11] = (byte)(num_regs & 0xff);
// send request
os.write(obuf, 0, 12);
// read response
i = is.read(ibuf, 0, 261);
if (i<9) {
if (i==0) {
System.out.println("unexpected close of connection at remote end");
} else {
System.out.println("response was too short - "+i+" chars");
}
} else if (0 != (ibuf[7] & 0x80)) {
System.out.println("MODBUS exception response - type "+ibuf[8]);
} else if (i != (9+2*num_regs)) {
System.out.println("incorrect response size is "+i+
" expected"+(9+2*num_regs));
} else {
for (i=0;i<=2;i++) {
int w = (ibuf[0+i+i]<<8) + ibuf[1+i+i];
System.out.println("word "+i+" = "+w);
}
for (i=3;i<=5;i++) {
int w = (ibuf[i+3]) ;
System.out.println("word "+i+" = "+w);
}
for (i=0;i<num_regs;i++) {
int w = (ibuf[9+i+i]<<8) + ibuf[10+i+i];
System.out.println("word "+i+" = "+w);
}
}
// close down
es.close();
} catch (Exception e) {
System.out.println("exception :"+e);
}
}
}
I want to use WikipediaTokenizer in lucene project - http://lucene.apache.org/java/3_0_2/api/contrib-wikipedia/org/apache/lucene/wikipedia/analysis/WikipediaTokenizer.html But I never used lucene. I just want to convert a wikipedia string into a list of tokens. But, I see that there are only four methods available in this class, end, incrementToken, reset, reset(reader). Can someone point me to an example to use it.
Thank you.
In Lucene 3.0, next() method is removed. Now you should use incrementToken to iterate through the tokens and it returns false when you reach the end of the input stream. To obtain the each token, you should use the methods of the AttributeSource class. Depending on the attributes that you want to obtain (term, type, payload etc), you need to add the class type of the corresponding attribute to your tokenizer using addAttribute method.
Following partial code sample is from the test class of the WikipediaTokenizer which you can find if you download the source code of the Lucene.
...
WikipediaTokenizer tf = new WikipediaTokenizer(new StringReader(test));
int count = 0;
int numItalics = 0;
int numBoldItalics = 0;
int numCategory = 0;
int numCitation = 0;
TermAttribute termAtt = tf.addAttribute(TermAttribute.class);
TypeAttribute typeAtt = tf.addAttribute(TypeAttribute.class);
while (tf.incrementToken()) {
String tokText = termAtt.term();
//System.out.println("Text: " + tokText + " Type: " + token.type());
String expectedType = (String) tcm.get(tokText);
assertTrue("expectedType is null and it shouldn't be for: " + tf.toString(), expectedType != null);
assertTrue(typeAtt.type() + " is not equal to " + expectedType + " for " + tf.toString(), typeAtt.type().equals(expectedType) == true);
count++;
if (typeAtt.type().equals(WikipediaTokenizer.ITALICS) == true){
numItalics++;
} else if (typeAtt.type().equals(WikipediaTokenizer.BOLD_ITALICS) == true){
numBoldItalics++;
} else if (typeAtt.type().equals(WikipediaTokenizer.CATEGORY) == true){
numCategory++;
}
else if (typeAtt.type().equals(WikipediaTokenizer.CITATION) == true){
numCitation++;
}
}
...
WikipediaTokenizer tf = new WikipediaTokenizer(new StringReader(test));
Token token = new Token();
token = tf.next(token);
http://www.javadocexamples.com/java_source/org/apache/lucene/wikipedia/analysis/WikipediaTokenizerTest.java.html
Regards
public class WikipediaTokenizerTest {
static Logger logger = Logger.getLogger(WikipediaTokenizerTest.class);
protected static final String LINK_PHRASES = "click [[link here again]] click [http://lucene.apache.org here again] [[Category:a b c d]]";
public WikipediaTokenizer testSimple() throws Exception {
String text = "This is a [[Category:foo]]";
return new WikipediaTokenizer(new StringReader(text));
}
public static void main(String[] args){
WikipediaTokenizerTest wtt = new WikipediaTokenizerTest();
try {
WikipediaTokenizer x = wtt.testSimple();
logger.info(x.hasAttributes());
Token token = new Token();
int count = 0;
int numItalics = 0;
int numBoldItalics = 0;
int numCategory = 0;
int numCitation = 0;
while (x.incrementToken() == true) {
logger.info("seen something");
}
} catch(Exception e){
logger.error("Exception while tokenizing Wiki Text: " + e.getMessage());
}
}
ObjectInputStream blocks when created until it recieves a serial input stream ans verifies it. I was trying to make my first program using sockets through it and found this. I used a dummy object so that it doesn't block. The code is here:
import java.io.*;
import java.net.*;
import java.util.*;
class Dummy implements Serializable {
}
class X_Int implements Serializable {
int x;
}
class Server {
public static void main(String args[]) throws Exception {
ServerSocket ss = new ServerSocket(5879);
Socket client = ss.accept();
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
out.writeObject(new Dummy());
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
in.readObject();
out.flush();
out.writeObject(new Date());
out.flush();
out.close();
}
}
class Client {
public static void main(String args[]) throws Exception {
Socket server = new Socket("localhost", 5879);
ObjectOutputStream out = new ObjectOutputStream(server.getOutputStream());
out.writeObject(new Dummy());
ObjectInputStream in = new ObjectInputStream(server.getInputStream());
in.readObject();
out.flush();
Date d = (Date)in.readObject();
System.out.println(d);
}
}
Is this the right way. Please comment.
You just need to flush() the output before creating the object input stream.
You don't need to send dummy objects.
A better way is to get rid of the cause of blocking in the first place. Use these classes instead on both ends, if you can:
public class ObjInputStream extends ObjectInputStream {
/**
* #param in
* #throws IOException
*/
public ObjInputStream(InputStream in) throws IOException {
super(in);
}
/* (non-Javadoc)
* #see java.io.ObjectInputStream#readStreamHeader()
*/
#Override
protected void readStreamHeader() throws IOException, StreamCorruptedException {
}
}
and
public class ObjOutputStream extends ObjectOutputStream {
/**
* #param out
* #throws IOException
*/
public ObjOutputStream(OutputStream out) throws IOException {
super(out);
}
/* (non-Javadoc)
* #see java.io.ObjectOutputStream#writeStreamHeader()
*/
#Override
protected void writeStreamHeader() throws IOException {
}
}
This removes the functions which are called to ascertain stream version info and such.
Additionally, as you are using TCP packets, IP fragmentation will cause your objects not be received 'whole' on the other end -- TCP is a stream socket. What you need is an additional framing input / output class. Luckily, I already coded this :)
/**
*
*/
package objtest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Queue;
import kokuks.KokuKS;
/**
* UnrealConceptTest - FramedInputStream
* #version 1.0
*/
public class FramedInputStream extends InputStream {
public static final int INITIAL_BUFFER_SIZE = 8 << 1;
public static final int FRAME_HEADER_1 = 0xBEEFFACE;
public static final int FRAME_HEADER_2 = 0xFACEBEEF;
public static final byte[] HEADER_BYTES = new byte[4 * 2];
protected static final byte[] CURR_HEADER_BUFF = new byte[HEADER_BYTES.length];
static {
ByteBuffer b = ByteBuffer.allocateDirect(8);
b.putInt(FRAME_HEADER_1);
b.putInt(FRAME_HEADER_2);
ByteBuffer b2 = (ByteBuffer) b.flip();
b2.get(HEADER_BYTES, 0, 4);
b2.get(HEADER_BYTES, 3, 4);
}
protected int size = 0;
protected int chain = 0;
protected boolean inFrame = false;
protected boolean readingSize = false;
protected int sizePos = 0;
protected int dbgput = 0;
protected ByteBuffer bb = ByteBuffer.allocateDirect(INITIAL_BUFFER_SIZE);
protected Queue<ByteBuffer> bbq = new ArrayDeque<ByteBuffer>();
protected ByteBuffer currBuff = null;
protected final boolean recoverFromError;
/**
*
*/
public FramedInputStream(boolean recoverFromError) {
this.recoverFromError = recoverFromError;
}
public FramedInputStream() {
this(true);
}
protected boolean ensureFramebufferCapacity(int min) {
int mymin = 1 << min;
if (mymin <= bb.capacity()) return false;
int num = bb.capacity();
while (num < mymin) num <<= 1;
ByteBuffer bb2 = ByteBuffer.allocateDirect(num);
// copy old data into new bytebuffer
int bb_pos = bb.position();
bb.rewind();
bb2.put(bb);
bb = bb2;
if (KokuKS.DEBUG_MODE) System.out.println("modified buffer size to: " + num);
return true;
}
/**
* #return the recoverFromError
*/
public boolean isRecoverFromError() {
return recoverFromError;
}
/* (non-Javadoc)
* #see java.io.InputStream#read()
*/
#Override
public int read() throws IOException {
if (currBuff == null || !currBuff.hasRemaining()) return -1;
byte b = currBuff.get();
//System.out.println("data: " + b);
return b;
}
public void putBuffer(ByteBuffer source) {
ensureFramebufferCapacity(bb.capacity() + source.remaining());
while (source.hasRemaining()) {
putByte(source.get());
}
}
public boolean checkCompleteFrame() {
return !bbq.isEmpty();
}
/* (non-Javadoc)
* #see java.io.InputStream#available()
*/
#Override
public int available() throws IOException {
return currBuff != null ? currBuff.remaining() : 0;
}
public int read(byte[] data) {
if (currBuff == null || !currBuff.hasRemaining()) {
return -1;
}
if (data.length > currBuff.remaining()) {
throw new BufferUnderflowException();
}
currBuff.get(data);
//System.out.println("data: " + new String(data));
return data.length;
}
public boolean nextFrame() {
ByteBuffer bbf = bbq.poll();
if (bbf != null) {
/*
System.out.println("bbf limit: " + bbf.limit());
System.out.println("bbf pos: " + bbf.position());
System.out.println("bbf data: " + new String(bbf.array()));
*/
//byte[] data = bbf.array();
//for (int i = 0; i < data.length; i++) {
// byte by = data[i];
// System.out.println("b: " + (by > 32 ? new String(new byte[] {by}) : "??") + ", " + by);
//}
currBuff = ByteBuffer.allocateDirect(bbf.limit());
currBuff.put(bbf).flip();
bbf.rewind();
/*
System.out.println("currbuf limit: " + currBuff.limit());
System.out.println("currbuf pos: " + currBuff.position());
System.out.println("currbuf data: " + new String(currBuff.array()));
*/
currBuff.rewind();
currBuff.position(1);
return true;
}
return false;
}
public void putByte(byte b) {
//System.out.println("pb b: " + ObjTest.getByteStr(b));
if (recoverFromError || !inFrame) {
if (b == HEADER_BYTES[chain++]) {
if (chain >= (HEADER_BYTES.length)) {
if (KokuKS.DEBUG_MODE) System.out.println("got header!" + (inFrame ? " (recovered)" : ""));
// we have a header! hurrah.
inFrame = true;
sizePos = 0;
size = 0;
readingSize = true;
chain = 0;
bb.clear();
}
} else {
chain = 0;
}
}
if (inFrame) {
if (readingSize) {
size += (b & 0xFF) << ((8 * 3) - (8 * sizePos));
//System.out.println("new size: " + size);
sizePos++;
if (sizePos >= 4) {
// we've read the size :)
readingSize = false;
sizePos = 0;
ensureFramebufferCapacity(size);
bb.clear();
bb.limit(size); // set buffer limit to size
//System.out.println("bb limit set to: " + bb.limit());
}
} else {
//System.out.println("put: " + dbgput++ + ", " + ObjTest.getByteStr(b));
bb.put(b);
if (!bb.hasRemaining()) {
bb.flip();
//System.out.println("bb limit after flip(): " + bb.limit());
//System.out.println("bblimit: " + bb.limit());
ByteBuffer newbuf = ByteBuffer.allocateDirect(bb.limit());
newbuf.put(bb).flip(); //we have to flip this
bbq.offer(newbuf);
//byte[] data = newbuf.array();
//for (int i = 0; i < newbuf.limit(); i++) {
// byte by = data[i];
// System.out.println("b: " + (by > 32 ? new String(new byte[] {by}) : "??") + ", " + by);
//}
inFrame = false;
readingSize = false;
size = 0;
sizePos = 0;
chain = 0;
bb.clear();
if (KokuKS.DEBUG_MODE) System.out.println("FIS: complete object");
//System.out.println("FIS: newbuf: " + new String(newbuf.array(), 0, newbuf.limit()));
}
}
}
}
}
and
/**
*
*/
package objtest;
import java.io.IOException;
import java.nio.ByteBuffer;
import koku.util.io.ByteBufferOutputStream;
/**
* UnrealConceptTest - FramedOutputStream
* #version 1.0
* #author Chris Dennett
*/
public class FramedOutputStream extends ByteBufferOutputStream {
public static final int FRAME_HEADER_1 = 0xBEEFFACE;
public static final int FRAME_HEADER_2 = 0xFACEBEEF;
public static final byte[] HEADER_BYTES = new byte[4 * 2];
public static final byte[] CURR_HEADER_BUFF = new byte[HEADER_BYTES.length];
/* We pad the beginning of our buffer so that we can write the frame
* length when the time comes. */
protected static final byte[] SIZE_PAD = new byte[4];
static {
ByteBuffer b = ByteBuffer.allocate(8);
b.putInt(FRAME_HEADER_1);
b.putInt(FRAME_HEADER_2);
ByteBuffer b2 = (ByteBuffer) b.flip();
b2.get(HEADER_BYTES, 0, 4);
b2.get(HEADER_BYTES, 3, 4);
}
/**
*
*/
public FramedOutputStream() {
try {
write(HEADER_BYTES);
write(SIZE_PAD);
} catch (IOException e) {
System.out.println("Couldn't write header padding!");
}
}
/* (non-Javadoc)
* #see koku.util.io.ByteBufferOutputStream#flip()
*/
#Override
public ByteBuffer flip() {
// flip the buffer which will limit it to it's current position
super.flip();
// then write the frame length and rewind back to the start of the
// buffer so that all the data is available
_buffer.position(11);
int size = _buffer.remaining();
//System.out.println("remaining after complete header: " + size);
_buffer.position(7);
//System.out.println("remaining after frameheader: " + _buffer.remaining());
putSizeAsBytes(size, _buffer);
//System.out.println("written size: " + size);
// System.out.println("buffer limit: " + _buffer.limit());
//System.out.println("_buffer: " + new String( _buffer.array(), 0, _buffer.limit()));
_buffer.position(11);
// System.out.println("_buffer11: " + ObjTest.getByteStr(_buffer.get()));
//System.out.println("_buffer12: " + ObjTest.getByteStr(_buffer.get()));
//System.out.println("_buffer13: " + ObjTest.getByteStr(_buffer.get()));
//System.out.println("_buffer14: " + ObjTest.getByteStr(_buffer.get()));
_buffer.rewind();
//_buffer.rewind();
//while (_buffer.hasRemaining()) {
// byte b = _buffer.get();
// System.out.println("b: " + (b > 32 ? new String(new byte[] {b}) : "??") + ", " + b);
//}
_buffer.rewind();
return _buffer;
}
/* (non-Javadoc)
* #see koku.util.io.ByteBufferOutputStream#reset()
*/
#Override
public void reset() {
super.reset();
try {
write(HEADER_BYTES);
write(SIZE_PAD);
} catch (IOException e) {
System.out.println("Couldn't write header padding!");
}
}
public static void putSizeAsBytes(int size, ByteBuffer bb) {
//System.out.println("putSizeAsBytes: given size: " + size);
// encode
for (int i = 0; i < 4; i++) {
bb.put((byte)((size >>> ((8 * 3) - (8 * i))) & 0xFF));
}
}
}
BBOS:
//
// $Id: ByteBufferOutputStream.java 5829 2009-06-20 21:09:34Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2009 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package misc;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import org.apache.mina.core.buffer.IoBuffer;
/**
* Stores output in an {#link ByteBuffer} that grows automatically to accommodate the data.
*/
public class ByteBufferOutputStream extends OutputStream
{
/**
* Creates a new byte buffer output stream.
*/
public ByteBufferOutputStream ()
{
_buffer = IoBuffer.allocate(INITIAL_BUFFER_SIZE);
}
/**
* Returns a reference to the underlying buffer.
*/
public IoBuffer getBuffer ()
{
return _buffer;
}
/**
* Flips and returns the buffer. The returned buffer will have a position of zero and a limit
* equal to the number of bytes written. Call {#link #reset} to reset the buffer before
* writing again.
*/
public IoBuffer flip ()
{
return _buffer.flip();
}
/**
* Resets our internal buffer.
*/
public void reset ()
{
_buffer.clear();
}
#Override // documentation inherited
public void write (int b)
{
try {
_buffer.put((byte)b);
} catch (BufferOverflowException boe) {
expand(1);
_buffer.put((byte)b);
}
}
#Override // documentation inherited
public void write (byte[] b, int off, int len)
{
// sanity check the arguments
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
try {
_buffer.put(b, off, len);
} catch (BufferOverflowException boe) {
expand(len);
_buffer.put(b, off, len);
}
}
/**
* Expands our buffer to accomodate the specified capacity.
*/
protected final void expand (int needed)
{
_buffer.expand(needed);
}
/** The buffer in which we store our frame data. */
protected IoBuffer _buffer;
/** The default initial size of the internal buffer. */
protected static final int INITIAL_BUFFER_SIZE = 32;
}