通过TCP套接字进行Avro通信

时间:2014-06-17 18:43:59

标签: java c sockets tcp avro

我目前正在开发一个涉及用C和Java编写的应用程序通信的项目。因此,我选择与Apache Avro合作。我在网站上看到Avro可以使用DataFileWriter类(文件)从文件中序列化对象。

但是,在我的情况下,我想在我的应用程序之间使用TCP套接字。因此,DataFileWriter类不适合我。阅读完文档后,我没有找到任何有关如何通过TCP套接字发送对象的信息。

关于如何做到这一点的任何想法?我特别想知道我应该在Java客户端上使用哪种输入和输出流。

我为Java Server开发了以下代码:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;

import middleman.bigpeer.BigPeer;

import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;

public class MiddleManWorker implements Runnable {

    private InputStream in;

    private OutputStream out;

    private Socket clientSocket;

    public MiddleManWorker(Socket clientSocket, HashMap<Integer, NodeType> dbNodesDirectory, 
            HashMap<Integer, NodeType>  workersDirectory) {
        this.clientSocket = clientSocket;
        try {
            this.in = clientSocket.getInputStream();
            this.out = clientSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        EncoderFactory encoderFactory = new EncoderFactory();
        DecoderFactory decoderFactory = new DecoderFactory();
    BinaryEncoder binaryEncoder = encoderFactory.binaryEncoder(out, null);
        BinaryDecoder binaryDecoder = decoderFactory.binaryDecoder(in, null);
        SpecificDatumReader<BigPeer> peerDatumReader = new SpecificDatumReader<BigPeer>(BigPeer.class);
        BigPeer bigPeer = null;
        SpecificDatumWriter<BigPeer> writer = new SpecificDatumWriter<BigPeer>();
        try {
            peerDatumReader.read(bigPeer, binaryDecoder);
            System.out.println("Received: " + bigPeer.getType());
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            writer.write(bigPeer, binaryEncoder);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

} 

示例Java客户端如下:

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

import middleman.bigpeer.BigPeer;

import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;

public class SystemClient {

    public static void connect(String serverIPAddress, Integer serverPort) throws IOException, ClassNotFoundException {
        /**
         * Create Connection with the server
         */
        Socket socket = new Socket(serverIPAddress, serverPort);
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();
        EncoderFactory encoderFactory = new EncoderFactory();
        DecoderFactory decoderFactory = new DecoderFactory();
        BinaryEncoder binaryEncoder = encoderFactory.binaryEncoder(out, null);
        BinaryDecoder binaryDecoder = decoderFactory.binaryDecoder(in, null);

        BigPeer bigPeer = new BigPeer();
        bigPeer.setType("test");
        SpecificDatumReader<BigPeer> reader = new SpecificDatumReader<BigPeer>(BigPeer.class);
        SpecificDatumWriter<BigPeer> writer = new SpecificDatumWriter<BigPeer>(BigPeer.class);

        System.out.println("Before: " +  bigPeer.getType());
        writer.write(bigPeer, binaryEncoder);
        System.out.println("Waiting for response...");
        reader.read(bigPeer, binaryDecoder);
        System.out.println("After: " + bigPeer.getType());
    }

}

服务器似乎停在peerDatumReader.read(bigPeer, binaryDecoder);代码行上。有什么想法吗?

谢谢你, 尼克

1 个答案:

答案 0 :(得分:1)

BinaryEncoder出于性能原因使用内部缓冲区。您可能需要在编码器上调用flush以通过管道发送数据。

有关此行为的详情,请参阅reference

  

返回的BinaryEncoder实现可以缓冲其输出。在调用Flushable.flush()之前,数据可能不会出现在底层的OutputStream上。缓冲区大小使用configureBufferSize(int)配置。

     

如果不需要缓冲,并且性能较低,请使用directBinaryEncoder(OutputStream,BinaryEncoder)