介绍

什么是Bencode?

Bencode(发音为 Bee-Encode)是BitTorrent用在传输数据结构的编码方式。

基本格式

string类型

string类型的编码格式为 [length]:[string]。以字符串的长度开头,加一个冒号,并以字符串内容结束。示例:

“abc” => 3:abc

int类型

int类型的编码格式为i[int]e。以i开头,加上数字,以e结尾。 示例:

123 => i123e

List类型

List类型的编码格式为l[object]e。以l开头,加上列表中各个元素的编码(元素的类型同样为BEncoding支持的类型),以e结尾。 示例:

List<“abc”, 123> => l3:abci123ee

Dictionary类型

Dictionary类型的编码格式为d[Key-Value Pair]e。以d开头,加上字典中每个键值对的编码,以e结尾。在java这种类型可以对应Map类型。示例:

Dictionary<{“name”:“lethe wi”},{“age”:12}> => d4:name8:lethe wi3:agei12ee

编码与解码实现

当前实现方式采用递归的思想进行实现,适用于数据量较小的情况下使用。

编码器

package studio.greeks.dht.util;

import java.util.List;
import java.util.Map;

/**
 * Created by Lethe on 2018/3/22. 
 */
public final class BCEncoder {
    public static String encode(Object object){
        return String.format("%se",BC_ENCODER.encodRouter(object));
    }

    private static final BCEncoder BC_ENCODER = new BCEncoder();
    private BCEncoder(){}

    private String encodeMap(Map map){
        StringBuilder builder = new StringBuilder();
        builder.append('d');
        for (Map.Entry entry : map.entrySet()) {
            builder.append(encodRouter(entry.getKey())).append(encodRouter(entry.getValue()));
        }
        builder.append('e');
        return builder.toString();
    }
    private String encodeString(String str){
        return String.format("%d:%s", str.length(), str);
    }
    private String encodeInteger(Integer integer){
        return String.format("i%de", integer);
    }
    private String encodeList(List list){
        StringBuilder builder = new StringBuilder();
        builder.append('l');
        for (Object o : list) {
            builder.append(encodRouter(o));
        }
        builder.append('e');
        return builder.toString();
    }
    private String encodRouter(Object object){
        if(object instanceof Map){
            return encodeMap((Map)object);
        }else if(object instanceof String){
            return encodeString((String)object);
        }else if(object instanceof List){
            return encodeList((List)object);
        }else if(object instanceof Integer){
            return encodeInteger((Integer)object);
        }else {
            return "";
        }
    }
}

解码器

package studio.greeks.dht.util;

import java.util.*;

/**
 * Created by Lethe on 2018/3/22. 
 */
public class BCDecoder {
    public static <T> T decode(String code, Class<T> tClass){
        // 将字符串变为一个字符栈
        char[] cs = code.toCharArray();
        Stack characterStack = new Stack();
        for (int i = cs.length-1; i >=0 ; i--) {
            characterStack.push(cs[i]);
        }
		
        // 使用解码路由方法进行自动开始解码
        Object obj = BC_DECODER.decodeRouter(characterStack);
        return tClass.cast(obj);
    }

    private static final BCDecoder BC_DECODER = new BCDecoder();
    private BCDecoder(){}

    
    private Map decodeMap(Stack characters){
        characters.pop(); // 去除d
        Map map = new LinkedHashMap();
        do {
            map.put(decodeString(characters), decodeRouter(characters));
        }while (!characters.peek().equals('e'));
        characters.pop(); // 去除e
        return map;
    }

    private String decodeString(Stack characters){
        StringBuilder builder = new StringBuilder();

        while(!characters.peek().equals(':')){
            builder.append(characters.pop());
        }
        int len = Integer.parseInt(builder.toString());

        characters.pop(); // 去除冒号

        builder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            builder.append(characters.pop());
        }

        return builder.toString();
    }

    private Integer decodeInteger(Stack characters){
        characters.pop();//去除i

        StringBuilder builder = new StringBuilder();
        while(!characters.peek().equals('e')){
            builder.append(characters.pop());
        }

        characters.pop();//去除e
        return new Integer(builder.toString());
    }

    private List decodeList(Stack characters){
        characters.pop(); // 去除l
        ArrayList objects = new ArrayList();
        do{
            objects.add(decodeRouter(characters));

        }while (!characters.peek().equals('e'));
        characters.pop(); // 去除e
        return objects;
    }

    private Object decodeRouter(Stack characters){
        char ic = characters.peek();
        switch (ic){
            case 'i':return decodeInteger(characters);
            case 'd':return decodeMap(characters);
            case 'l':return decodeList(characters);
            default:
                if('0'<=ic && ic <= '9') {
                    return decodeString(characters);
                }else {
                    return null; // 异常
                }
        }
    }
}

——————————————————————————
行路不知花开处,蓦然回首芷兰香。