0

这段代码应该将两个方向的流视为一个流。例如:

srcAddr,dstAddr,srcPort,dstPort
192.168.1.65, 217.174.16.1, 123456,80

应该是一样的

217.174.16.1, 192.168.1.65,80,123456

另一个例子:

192.168.1.65, 217.174.16.1, 12345, 80, TCP
217.174.16.1, 192.168.1.65, 80, 12345, TCP
192.168.1.65, 217.174.16.1, 12345, 80, TCP
217.174.16.1, 192.168.1.65, 80, 12345, TCP

我想保持这样:

Flow 1: key---> value (keeps statistics about each packet, like length and timeArrival)

[192.168.1.65, 217.174.16.1, 12345, 80] ----> [(outgoing, 1,2)(incoming,3,4)()()...]

192.168.1.65, 69.100.70.80, 98521, 80 69.100.70.80, 192.168.1.65, 80, 98521 192.168.1.65, 69.100.70.80, 98521, 80 69.100.70.80, 192.168.1.65, 80, 98521 192.168.1.65, 69.100.70.80, 98521, 80 69.100.70.80, 192.168.1.65, 80, 98521

Flow 2: [192.168.1.65, 69.100.70.80, 98521, 80] --> [(outgoing, 1,2)(incoming,3,4)()()...]

我应该如何改变它以获得结果?[我使用 hashMap 并且这类 Flows 是我的关键]

 package myclassifier;
 public class Flows implements Comparable<Flows> {

String srcAddr = "", dstAddr = "", protocol = "";
int srcPort = 0, dstPort = 0;

public Flows(String sIP, String dIP, int sPort, int dPort){
    this.srcAddr = sIP;
    this.dstAddr = dIP;
    this.srcPort = sPort;
    this.dstPort = dPort;
    //this.protocol = protocol;

}
public Flows(){

}

public int compareTo(Flows other) {
    int res = 1;
    if(this.equals(other)){
        return res=0;
    }else
        return 1;
}



 @Override
public int hashCode() {

    final int prime = 31;
    int result = 1;
    result = prime * result + ((dstAddr == null) ? 0 : dstAddr.hashCode());
    result = prime * result + dstPort;
    result = prime * result + ((srcAddr == null) ? 0 : srcAddr.hashCode());
    result = prime * result + srcPort;
    return result;

}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;

    if (getClass() != obj.getClass())
        return false;

    Flows other = (Flows) obj;

    if (dstAddr == null) {
        if (other.dstAddr != null)
            return false;
    } else if (!dstAddr.equals(other.dstAddr))
        return false;
    if (dstPort != other.dstPort)
        return false;
    if (srcAddr == null) {
        if (other.srcAddr != null)
            return false;
    } else if (!srcAddr.equals(other.srcAddr))
        return false;
    if (srcPort != other.srcPort)
        return false;
    return true;

}

 @Override
public String toString() {
return String.format("[%s, %s, %s, %s, %s]", srcAddr, dstAddr, srcPort, dstPort, protocol);
}


}
4

3 回答 3

2

可能最干净的方法是定义这些方法:

  • Flows reverse()Flows返回给定的相反方向Flows
  • Flows canon()它返回 a 的规范化形式Flows
    • 您可以定义例如 a Flowsis canon ifsrcAddr.compareTo(dstAddr) <= 0
    • 否则,reverse()根据定义,它是佳能

然后对于非定向比较,您可以简单地比较两个流的规范形式。拥有这些方法使其余的逻辑非常清晰易读(参见下面的代码)。


关于Comparator, Comparable, 和一致性equals

使用reverse()上面的概念,如果你f.equals(f.reverse())总是想要,那么也许一开始就不应该有任何方向性的概念。如果是这种情况,那么规范化是最好的方法。

如果f通常不是equals(f.reverse()),但您可能希望fandf.reverse()与 0 进行比较,则Comparable不应使用 then,因为这样做会施加与 equals 不一致的自然顺序。

从文档中:

一个类的自然顺序C被认为是 equals当且仅当具有与类的每个和e1.compareTo(e2) == 0相同的布尔值时一致的。e1.equals(e2)e1e2C

强烈建议(尽管不是必需的)自然排序与equals.

也就是说,与其强加Comparable与 不一致的自然排序,不如equals提供一个非定向的Comparator

作为类比,将这种情况与 比较String,它提供了Comparator<String> CASE_INSENSITIVE_ORDER,它允许两个字符串equals不区分大小写而与 0 进行比较。

因此,在这里您将编写一个Comparator<Flows>允许两个Flowsequals通过方向不敏感与 0 进行比较的值。

也可以看看

相关问题


示例实现

这是一个类的示例实现,Edge该类具有fromand to,具有与 一致的定向自然排序,equals它还提供了非定向Comparator.

然后用 3 种测试Set

  • A HashSet, 测试equalshashCode
  • A TreeSet、测试自然排序
  • ATreeSet与 custom Comparator,以测试非方向性

实施简洁明了,应该具有指导意义。

import java.util.*;

class Edge implements Comparable<Edge> {
    final String from, to;
        
    public Edge(String from, String to) {
        this.from = from;
        this.to = to;
    }
    @Override public String toString() {
        return String.format("%s->%s", from, to);
    }
    public Edge reverse() {
        return new Edge(to, from);
    }
    public Edge canon() {
        return (from.compareTo(to) <= 0) ? this : this.reverse();
    }
    @Override public int hashCode() {
        return Arrays.hashCode(new Object[] {
            from, to
        });
    }   
    @Override public boolean equals(Object o) {
        return (o instanceof Edge) && (this.compareTo((Edge) o) == 0);
    }
    @Override public int compareTo(Edge other) {
        int v;

        v = from.compareTo(other.from);
        if (v != 0) return v;

        v = to.compareTo(other.to);
        if (v != 0) return v;

        return 0;
    }
    public static Comparator<Edge> NON_DIRECTIONAL =
        new Comparator<Edge>() {
            @Override public int compare(Edge e1, Edge e2) {
                return e1.canon().compareTo(e2.canon());
            }
        };
}

public class Main {
    public static void main(String[] args) {
        testWith(new HashSet<Edge>());
        testWith(new TreeSet<Edge>());
        testWith(new TreeSet<Edge>(Edge.NON_DIRECTIONAL));
    }
    public static void testWith(Set<Edge> set) {
        set.clear();
        set.add(new Edge("A", "B"));
        set.add(new Edge("C", "D"));
        System.out.println(set.contains(new Edge("A", "B")));
        System.out.println(set.contains(new Edge("B", "A")));
        System.out.println(set.contains(new Edge("X", "Y")));
        System.out.println(set);
        set.add(new Edge("B", "A"));
        set.add(new Edge("Z", "A"));
        System.out.println(set);
        System.out.println();
    }
}

输出如下(见 ideone.com),注释:

// HashSet
// add(A->B), add(C->D)
true    // has A->B?
false   // has B->A?
false   // has X->Y?
[C->D, A->B]
// add(B->A), add(Z->A)
[B->A, C->D, Z->A, A->B]

// TreeSet, natural ordering (directional)    
// add(A->B), add(C->D)
true    // has A->B?
false   // has B->A?
false   // has X->Y
[A->B, C->D]
// add(B->A), add(Z->A)
[A->B, B->A, C->D, Z->A]

// TreeSet, custom comparator (non-directional)
// add(A->B), add(C->D)
true    // has A->B?
true    // has B->A?
false   // has X->Y?
[A->B, C->D]
// add(B->A), add(Z->A)
[A->B, Z->A, C->D]

请注意,在非定向TreeSet中,Z->A被规范化为A->Z,这就是它C->D按此顺序出现在前面的原因。类似地,B->A被规范化为A->B,它已经在集合中,这就解释了为什么那里只有 3 个Edge

关键点

  • Edge是不可变的
  • Arrays.hashCode(Object[])用于方便;无需编写所有公式
  • 如果自然排序与 一致equals,则可以使用compareTo == 0inequals
  • 为了简洁明了,使用多步return逻辑compareTo
  • 具有reverse()canon()大大简化了非定向比较
    • 只需按自然顺序比较它们的规范化形式

也可以看看

  • 有效的 Java 第 2 版
    • 第 8 条:超驰时遵守总合同equals
    • hashCode第 9 项:覆盖时始终覆盖equals
    • 第 10 项:始终覆盖toString
    • 第 12 项:考虑实施Comparable
    • 第 15 条:最小化可变性
    • 第 36 条:始终如一地使用@Override注解
    • 第 47 条:了解和使用库
于 2010-08-17T09:41:52.090 回答
0

关键是正确实现equals方法。在您的 equals 方法中,当目标地址不匹配时,您将返回 false。这是您需要添加额外逻辑来检查相等性的地方,因为您希望具有双向相等性。相等性的第一遍应该是检查源、目的地、端口的相等性。第二遍应该是源和目标的反向相等。您还需要对默认值进行特殊规定,例如在您的示例中,排除 portno(80) 默认为 true。

于 2010-08-17T09:54:27.407 回答
0

我不知道这是否对你有帮助。但正如你所说,它在两个方向都有效

import java.util.HashSet;
 public class Flows implements Comparable<Flows> {

String srcAddr = "", dstAddr = "", protocol = "";
int srcPort = 0, dstPort = 0;

public Flows(String sIP, String dIP, int sPort, int dPort){
    this.srcAddr = sIP;
    this.dstAddr = dIP;
    this.srcPort = sPort;
    this.dstPort = dPort;
    //this.protocol = protocol;

}
public Flows(){

}

public int compareTo(Flows other) {

    if(this.equals(other)){
        return 0;
    }else
        return 1;
}



 @Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((dstAddr == null) ? 0 : dstAddr.hashCode())+((srcAddr == null) ? 0 : srcAddr.hashCode());
    result = prime * result + dstPort+srcPort;
    return result;

}

@Override
public boolean equals(Object obj) {
   if (this == obj)
        return true;

   if(obj instanceof Flows)
   {
    Flows c=(Flows)obj;
    if(srcAddr.equals(c.dstAddr) && dstAddr.equals(c.srcAddr) &&srcPort==c.dstPort && dstPort==c.srcPort)
      return true;

    if(srcAddr.equals(c.srcAddr) && dstAddr.equals(c.dstAddr) && srcPort==c.srcPort && dstPort==c.dstPort)
        return true;
   }
    return false;

}

 @Override
public String toString() {
return String.format("[%s, %s, %s, %s, %s]", srcAddr, dstAddr, srcPort, dstPort, protocol);
}

public static void main(String[] args) {
    Flows f1=new Flows("192.168.1.65","217.174.16.1", 123456,80);
    Flows f2=new Flows("217.174.16.1","192.168.1.65",80,123456);

    Flows f3=new Flows("192.168.1.66","217.174.16.1", 123456,80);
    Flows f4=new Flows("217.174.16.1","192.168.1.66",80, 123456);
    System.out.println(f1.hashCode()+ " "+f2.hashCode());
    HashSet<Flows> hh=new HashSet<Flows>();
    hh.add(f1);
    hh.add(f2);
    hh.add(f3);
    hh.add(f4);
    System.out.println(f1.compareTo(f2));
    System.out.println(hh);
}
}

我已经使用 hashset 进行测试。所以它也应该适用于 hashmap。

于 2010-08-17T10:51:11.200 回答