原理在上一篇已经说好了,在这就不再赘述了,直接上代码,代码只是实现了一个基本框架,需要完善的东西大家可以自己加:
NamedPipe.java
public class NamedPipe implements Pipe { static{ System.loadLibrary("NPJNI"); } NamedPipeInputStream is; NamedPipeOutputStream os; int handle = -1; private String name; public String getName() { return name; } public NamedPipe(String name){ this.name = name; this.handle = this.create(name); if(handle == -1){ throw new NamedPipeCreateException(name); } } /** * 等待接受一个客户端连接(堵塞) * @return */ public boolean accept(){ return this.connect(this.handle); } /** * 得到一个PipeInputStream以读入数据 */ public PipeInputStream getInputStream() { if(is == null){ is = new NamedPipeInputStream(this); } return is; } /** * 得到一个PipeOutputStream以写入数据 */ public PipeOutputStream getOutputStream() { if(os == null){ os = new NamedPipeOutputStream(this); } return os; } /** * 关闭此NamedPipe */ public void close() { if(this.handle != -1){ this.close(this.handle); } } /** * 断开当前的客户端连接 */ public void disconnect(){ disconnect(handle); } private native void disconnect(int handle); private native void close(int handle); private native int create(String name); private native boolean connect(int handle); }
NamedPipeInputStream:
public class NamedPipeInputStream extends PipeInputStream { NamedPipe pipe; static{ System.loadLibrary("NPJNI"); } NamedPipeInputStream(NamedPipe pipe){ this.pipe = pipe; } private native int readBytes(int handle, byte b[], int len) throws IOException; /** * 读入数据到一个beye数组(堵塞) * @return 实际读取的字节数 */ public int read(byte b[]) throws IOException { return readBytes(pipe.handle, b, b.length); } /** * 读入数据到一个beye数组(堵塞) * @param b * @return 读取信息 */ public ReadPipeInfo readPipe(byte b[]){ return this.readPipe(pipe.handle,b,b.length); } public native ReadPipeInfo readPipe(int handle, byte b[], int len); }
NamedPipeOutputStream.java:
public class NamedPipeOutputStream extends PipeOutputStream { NamedPipe pipe; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); static{ System.loadLibrary("NPJNI"); } NamedPipeOutputStream(NamedPipe pipe){ this.pipe = pipe; } /*public final NamedPipe getPipe(){ return pipe; }*/ private native void writeBytes(int handle, byte b[], int len) throws IOException; private native void writeBytesOff(int handle, byte b[], int offset, int len) throws IOException; /** * 将一个byte数组写入管道 */ public void write(byte b[]) throws IOException { buffer.write(b); } /** * 将字符串s写入管道 * @throws IOException */ public void write(String s) throws IOException{ buffer.write(s.getBytes()); } /** * 将byte数组写入管道。off指定了写入的偏移值,len指定写入的长度 */ @Override public void write(byte[] b, int off, int len) throws IOException { this.writeBytesOff(pipe.handle,b,off,len); } /** * flush此NamedPipeOutputStream,将所有数据写入管道 */ public void flush() { byte[] bytes = buffer.toByteArray(); if(bytes.length > 0){ try { writeBytes(pipe.handle, bytes, bytes.length); } catch (IOException e) { e.printStackTrace(); } buffer = new ByteArrayOutputStream(); flush(pipe.handle); } } private native void flush(int handle); }
ReadPipeInfo.java:
public class ReadPipeInfo { boolean more = false; int count = -1; public boolean hasMoreData(){ return this.more; } public int readCount(){ return count; } }
C++代码:
#define BUFSIZE 4096*500 JNIEXPORT jint JNICALL Java_pipe_NamedPipe_create (JNIEnv *env, jobject obj, jstring name) { const wchar_t *str = (const wchar_t *)env->GetStringChars(name,NULL); if(str == NULL) { return -1; } HANDLE hPipe; hPipe = CreateNamedPipe( str, // pipe name PIPE_ACCESS_DUPLEX, // read/write access PIPE_TYPE_MESSAGE | // message type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode PIPE_UNLIMITED_INSTANCES, // max. instances BUFSIZE, // output buffer size BUFSIZE, // input buffer size 0, // client time-out NULL); // default security attribute if (hPipe == INVALID_HANDLE_VALUE) { env->ReleaseStringChars(name, (const jchar *)str); printf("CreatePipe failed"); return -1; } env->ReleaseStringChars(name, (const jchar *)str); return (long)hPipe; } JNIEXPORT jboolean JNICALL Java_pipe_NamedPipe_connect (JNIEnv *env, jobject obj, jint handle) { HANDLE hPipe = (void *)((int)handle); BOOL fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); return fConnected; } JNIEXPORT void JNICALL Java_pipe_NamedPipe_close (JNIEnv *env, jobject obj, jint handle) { CloseHandle((void *)((int)handle)); } JNIEXPORT void JNICALL Java_pipe_NamedPipe_disconnect (JNIEnv *env, jobject obj, jint handle) { HANDLE hPipe = (void *)((int)handle); DisconnectNamedPipe(hPipe); } JNIEXPORT jint JNICALL Java_pipe_NamedPipeInputStream_readBytes (JNIEnv *env, jobject obj, jint handle, jbyteArray buffer, jint len) { //jbyte *jBuffer = env->GetByteArrayElements(buffer,NULL); char *cBuffer = new char[len+1]; DWORD cbBytesRead; HANDLE hPipe = (void *)((int)handle); BOOL fSuccess = ReadFile( hPipe, // handle to pipe cBuffer, // buffer to receive data len, // size of buffer &cbBytesRead, // number of bytes read NULL); // not overlapped I/O if (! fSuccess && GetLastError() != ERROR_MORE_DATA) { delete cBuffer; return -1; } env->SetByteArrayRegion(buffer,0,cbBytesRead,(const jbyte *)cBuffer); delete cBuffer; return cbBytesRead; } JNIEXPORT jobject JNICALL Java_pipe_NamedPipeInputStream_readPipe (JNIEnv *env, jobject obj, jint handle, jbyteArray buffer, jint len) { //jbyte *jBuffer = env->GetByteArrayElements(buffer,NULL); char *cBuffer = new char[len+1]; DWORD cbBytesRead; HANDLE hPipe = (void *)((int)handle); BOOL fSuccess = ReadFile( hPipe, // handle to pipe cBuffer, // buffer to receive data len, // size of buffer &cbBytesRead, // number of bytes read NULL); // not overlapped I/O DWORD le = GetLastError(); if (! fSuccess && le != ERROR_MORE_DATA) { jclass jclass = env->FindClass("pipe/ReadPipeInfo"); jfieldID moreData = env->GetFieldID(jclass,"more","Z"); jfieldID count = env->GetFieldID(jclass,"count","I"); jmethodID mID = env->GetMethodID(jclass, "<init>", "()V"); jobject info = env->NewObject(jclass,mID); delete cBuffer; env->SetBooleanField(info,moreData,false); env->SetIntField(info,count,-1); env->DeleteLocalRef(jclass); return info; } jclass jclass = env->FindClass("pipe/ReadPipeInfo"); jfieldID moreData = env->GetFieldID(jclass,"more","Z"); jfieldID count = env->GetFieldID(jclass,"count","I"); jmethodID mID = env->GetMethodID(jclass, "<init>", "()V"); jobject info = env->NewObject(jclass,mID); env->SetByteArrayRegion(buffer,0,cbBytesRead,(const jbyte *)cBuffer); delete cBuffer; if(le == ERROR_MORE_DATA){ env->SetBooleanField(info,moreData,true); }else{ env->SetBooleanField(info,moreData,false); } env->SetIntField(info,count,cbBytesRead); //env->SetShortField(info,count,10); env->DeleteLocalRef(jclass); return info; } JNIEXPORT void JNICALL Java_pipe_NamedPipeOutputStream_writeBytes (JNIEnv *env, jobject obj, jint handle, jbyteArray buffer, jint len) { jbyte *jBuffer = env->GetByteArrayElements(buffer,NULL); DWORD cbWritten; HANDLE hPipe = (void *)((int)handle); // Write to the pipe. BOOL fSuccess = WriteFile( hPipe, // handle to pipe jBuffer, // buffer to write from len, // number of bytes to write &cbWritten, // number of bytes written NULL); // not overlapped I/O } JNIEXPORT void JNICALL Java_pipe_NamedPipeOutputStream_writeBytesOff (JNIEnv *env, jobject obj, jint handle, jbyteArray buffer, jint off, jint len) { jbyte *jBuffer = env->GetByteArrayElements(buffer,NULL); DWORD cbWritten; HANDLE hPipe = (void *)((int)handle); // Write to the pipe. BOOL fSuccess = WriteFile( hPipe, // handle to pipe jBuffer+off, // buffer to write from len, // number of bytes to write &cbWritten, // number of bytes written NULL); // not overlapped I/O } JNIEXPORT void JNICALL Java_pipe_NamedPipeOutputStream_flush (JNIEnv *env, jobject obj, jint handle) { HANDLE hPipe = (void *)((int)handle); BOOL flag = FlushFileBuffers(hPipe); }