原理在上一篇已经说好了,在这就不再赘述了,直接上代码,代码只是实现了一个基本框架,需要完善的东西大家可以自己加:
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);
}