如何在jgroups中组播大文件

时间:2016-01-22 16:25:04

标签: java multicast jgroups

假设我有一个相对较大的文件(大约100MB),我想要多播到群集的所有成员。如何使用jgroups(最好是代码演示)以块的形式发送文件?应该在接收器端以块的形式读取该文件。另外,我如何确保在接收方保持块的顺序顺序。

编辑1 这是我到目前为止所尝试的。我只是将文件作为一个整体发送,并将其内容在接收方的一侧写入临时文件

    public class SimpleFileTransfer extends ReceiverAdapter {

    JChannel channel;

    private void start() throws Exception{
        channel = new JChannel();
        channel.setReceiver(this);
        channel.connect("FileCluster");
//        channel.getState(null, 10000);
        File file = new File("/res/test.txt"); //the file to be sent
        eventLoop(file);
        channel.close();
    }

    private void eventLoop(File file) throws IOException{
        BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        try {
            Message msg = new Message(null, null, in);
            channel.send(msg);
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }


    public void receive(Message msg)
    {
        try {
            File temp = new File("/res/temp.txt");
            FileWriter writer = new FileWriter(temp);
            InputStream in = new ByteArrayInputStream(msg.getBuffer());
            int next = in.read();
            while (next != -1){
                writer.write(next);
                next = in.read();
            }
        }
        catch (IOException ie)
        {
            ie.printStackTrace();
        }


    }

}

3 个答案:

答案 0 :(得分:3)

下面是更好的版本,它将大文件分成8K的块。 文件X写入/ tmp / X.请注意,必须更改/home/bela/fast.xml配置:

public class SimpleFileTransfer extends ReceiverAdapter {
protected String   filename;
protected JChannel channel;
protected Map<String,OutputStream> files=new ConcurrentHashMap<>();
protected static final short ID=3500;

private void start(String name, String filename) throws Exception {
    ClassConfigurator.add((short)3500, FileHeader.class);
    this.filename=filename;
    channel=new JChannel("/home/bela/fast.xml").name(name);
    channel.setReceiver(this);
    channel.connect("FileCluster");
    eventLoop();
}

private void eventLoop() throws Exception {
    while(true) {
        Util.keyPress(String.format("<enter to send %s>\n", filename));
        sendFile();
    }
}

protected void sendFile() throws Exception {
    FileInputStream in=new FileInputStream(filename);
    try {
        for(;;) {
            byte[] buf=new byte[8096];
            int bytes=in.read(buf);
            if(bytes == -1)
                break;
            sendMessage(buf, 0, bytes, false);
        }
    }
    catch(Exception e) {
        e.printStackTrace();
    }
    finally {
        sendMessage(null, 0, 0, true);
    }
}


public void receive(Message msg) {
    byte[] buf=msg.getRawBuffer();
    FileHeader hdr=(FileHeader)msg.getHeader(ID);
    if(hdr == null)
        return;
    OutputStream out=files.get(hdr.filename);
    try {
        if(out == null) {
            File tmp=new File(hdr.filename);
            String fname=tmp.getName();
            fname="/tmp/" + fname;
            out=new FileOutputStream(fname);
            files.put(hdr.filename, out);
        }
        if(hdr.eof) {
            Util.close(files.remove(hdr.filename));
        }
        else {
            out.write(msg.getRawBuffer(), msg.getOffset(), msg.getLength());
        }
    }
    catch(Throwable t) {
        System.err.println(t);
    }
}


protected void sendMessage(byte[] buf, int offset, int length, boolean eof) throws Exception {
    Message msg=new Message(null, buf, offset, length).putHeader(ID, new FileHeader(filename, eof));
    // set this if the sender doesn't want to receive the file
    // msg.setTransientFlag(Message.TransientFlag.DONT_LOOPBACK);
    channel.send(msg);
}

protected static class FileHeader extends Header {
    protected String  filename;
    protected boolean eof;

    public FileHeader() {} // for de-serialization

    public FileHeader(String filename, boolean eof) {
        this.filename=filename;
        this.eof=eof;
    }

    public int size() {
        return Util.size(filename) + Global.BYTE_SIZE;
    }

    public void writeTo(DataOutput out) throws Exception {
        Util.writeObject(filename, out);
        out.writeBoolean(eof);
    }

    public void readFrom(DataInput in) throws Exception {
        filename=(String)Util.readObject(in);
        eof=in.readBoolean();
    }
}

public static void main(String[] args) throws Exception {
    if(args.length != 2) {
        System.out.printf("%s <name> <filename>\n", SimpleFileTransfer.class.getSimpleName());
        return;
    }
    new SimpleFileTransfer().start(args[0], args[1]); // name and file
}

}

答案 1 :(得分:1)

以下是糟糕的解决方案。要运行它,配置需要有bundler_type =&#34; sender-sending&#34; (在UDP中)并且应用程序需要足够的内存。 这个解决方案很糟糕,因为它将整个文件读入缓冲区,在JGroups中也会复制两次。 我发布的下一个解决方案更好,因为它将大文件分块为多个较小的块。请注意,发送大文件,JGroups也会执行内部分块(碎片),但是你仍然需要在应用程序级别创建那个大的byte []缓冲区,这很糟糕。

public class SimpleFileTransfer extends ReceiverAdapter {
protected String   filename;
protected JChannel channel;

private void start(String name, String filename) throws Exception {
    this.filename=filename;
    channel=new JChannel("/home/bela/fast.xml").name(name);
    channel.setReceiver(this);
    channel.connect("FileCluster");
    eventLoop();
    channel.close();
}

private void eventLoop() throws Exception {
    while(true) {
        Util.keyPress(String.format("<enter to send %s>\n", filename));
        sendFile();
    }
}

protected void sendFile() throws Exception {
    Buffer buffer=readFile(filename);
    try {
        Message msg=new Message(null, buffer);
        channel.send(msg);
    }
    catch(Exception e) {
        e.printStackTrace();
    }
}


public void receive(Message msg) {
    System.out.printf("received %s from %s\n", Util.printBytes(msg.getLength()), msg.src());
    try {
        File temp=new File("/tmp/temp.txt");
        FileWriter writer=new FileWriter(temp);
        InputStream in=new ByteArrayInputStream(msg.getBuffer());
        int next=in.read();
        while(next != -1) {
            writer.write(next);
            next=in.read();
        }
    }
    catch(IOException ie) {
        ie.printStackTrace();
    }
}


protected static Buffer readFile(String filename) throws Exception {
    File file=new File(filename);
    int size=(int)file.length();
    FileInputStream input=new FileInputStream(file);
    ByteArrayDataOutputStream out=new ByteArrayDataOutputStream(size);
    byte[] read_buf=new byte[1024];
    int bytes;
    while((bytes=input.read(read_buf)) != -1)
        out.write(read_buf, 0, bytes);
    return out.getBuffer();
}


public static void main(String[] args) throws Exception {
    if(args.length != 2) {
        System.out.printf("%s <name> <filename>\n", SimpleFileTransfer.class.getSimpleName());
        return;
    }
    new SimpleFileTransfer().start(args[0], args[1]); // name and file
}

}

答案 2 :(得分:0)

没有人会为你编写代码,但是:

  1. 将文件转换为字节数组
  2. 将数组分成块
  3. 将每个块包裹在一个信封中,说明它是哪个
  4. 发送块
  5. 阅读信封将它们重新组合在一起
  6. 这些事情都不是很难。