有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java从controller1向controller2发送消息

我在mininet中有一个拓扑结构,它由两个泛光灯控制器(c1和c2)、一个连接到c1的交换机(s1)和两个连接到此交换机的主机(h1和h2)组成。我正在编写一个程序,当c1从s1接收到ICMP数据包时,它将向c2发送一条Hello消息

我使用这个tutorial是为了这个目的,它说:

Messages can be sent from one controller to another using the send function, and the messages have to be tagged with an ‘m’ “m”. You will send this message TO a particular controller so the TO address comprises of two parts IP:port. The IP is the machine IP address of the other controller (HAServer is listening on all ips), and the port is the corresponding listening port of HAServer on that machine.

By default, HAServer on controller 1 is listening on 4242, on controller 2 on 4243, on controller 3 on 4244 … and so on.

recv() function is similar to the send function and you will be giving the FROM address to hear back FROM a particular controller. The from address also comprises of two parts, IP:port. The IP is the machine IP address of the other controller (HAServer is listening on all ips), and the port is the corresponding listening port of HAServer on that machine.

Ideally, this function is called after calling a corresponding send() function, otherwise, a connection might not have been established, and it will just return an error.

以下是我的模块的完整代码:

package net.floodlightcontroller.mactracker;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.hasupport.IHAControllerService;
import net.floodlightcontroller.hasupport.NetworkNode;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.ICMP;
import net.floodlightcontroller.packet.IPv4;

import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IpProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Mactracker implements IFloodlightModule, IOFMessageListener {

    protected static IHAControllerService hacontroller;
    protected static Logger logger = LoggerFactory.getLogger(Mactracker.class);
    protected IFloodlightProviderService floodlightProvider;
    protected Set<Long> macAddresses;
    private static NetworkNode network;

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
        // TODO Auto-generated method stubs
        return null;
    }

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
        // TODO Auto-generated method stub
        Collection<Class<? extends IFloodlightService>> l =
                new ArrayList<Class<? extends IFloodlightService>>();
            l.add(IFloodlightProviderService.class);
            l.add(IHAControllerService.class);
        return l;
    }

    @Override
    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
        // TODO Auto-generated method stub
        hacontroller = context.getServiceImpl(IHAControllerService.class);
        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
        macAddresses = new ConcurrentSkipListSet<Long>();
    }

    @Override
    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
        // TODO Auto-generated method stub
        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
        // After more than 51% of configured controllers are started, this function will return,
        // or when a timeout of 60s is reached, whichever is earlier.
        hacontroller.pollForLeader();       
    }

    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return Mactracker.class.getSimpleName();
    }

    @Override
    public boolean isCallbackOrderingPrereq(OFType type, String name) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isCallbackOrderingPostreq(OFType type, String name) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public net.floodlightcontroller.core.IListener.Command receive(IOFSwitch sw, OFMessage msg,
            FloodlightContext cntx) {
        // TODO Auto-generated method stub
        Ethernet eth =
                IFloodlightProviderService.bcStore.get(cntx,
                                            IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
        if (eth.getEtherType() == EthType.IPv4) {
            IPv4 ipv4 = (IPv4) eth.getPayload();

            if ( ipv4.getProtocol().equals(IpProtocol.ICMP)){
                logger.warn ("ICMP Packet Received!:-)");
                ICMP icmp = (ICMP) ipv4.getPayload();
                logger.warn ("icmp.getIcmpType: "+icmp.getIcmpType());

                hacontroller.send("127.0.0.1:4243", "mHelloWorld");
                hacontroller.recv("127.0.0.1:4242");
            }
        }

        Long sourceMACHash = eth.getSourceMACAddress().getLong();
        if (!macAddresses.contains(sourceMACHash)) {
            macAddresses.add(sourceMACHash);
            logger.info("MAC Address: {} seen on switch: {}",
                    eth.getSourceMACAddress().toString(),
                    sw.getId().toString());
        }
        return Command.CONTINUE;
    }
}

但运行此代码后,当c1收到ICMP数据包时,我遇到多个错误:

2018-09-13 00:39:56.716 WARN  [n.f.m.Mactracker] ICMP Packet Received!:-)
2018-09-13 00:39:56.716 WARN  [n.f.m.Mactracker] icmp.getIcmpType: 0
2018-09-13 00:39:56.716 INFO  [n.f.h.NetworkNode] [NetworkNode] Sending: mHelloWorld sent through port: 127.0.0.1:4243
2018-09-13 00:39:56.720 WARN  [i.n.c.DefaultChannelPipeline] An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.NullPointerException: null
    at net.floodlightcontroller.hasupport.NetworkNode.recv(NetworkNode.java:535) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.hasupport.HAController.recv(HAController.java:190) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.mactracker.Mactracker.receive(Mactracker.java:121) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.Controller.handleMessage(Controller.java:411) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchManager.handleMessage(OFSwitchManager.java:487) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.dispatchMessage(OFSwitchHandshakeHandler.java:1752) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.access$24(OFSwitchHandshakeHandler.java:1751) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler$MasterState.processOFPacketIn(OFSwitchHandshakeHandler.java:1488) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler$OFSwitchHandshakeState.processOFMessage(OFSwitchHandshakeHandler.java:839) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.processOFMessage(OFSwitchHandshakeHandler.java:1790) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.messageReceived(OFSwitchHandshakeHandler.java:1964) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFConnection.messageReceived(OFConnection.java:414) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFChannelHandler.sendMessageToConnection(OFChannelHandler.java:579) [floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFChannelHandler.access$9(OFChannelHandler.java:578) [floodlight.jar:1.2-SNAPSHOT]

有什么问题吗?recv()函数似乎有问题。下面是内置的send()和receive函数的代码

send():

/**
 * Sends a message to a specified client IP:port, if possible.
 *
 * @return boolean value that indicates success or failure.
 */

@Override
public Boolean send(String clientPort, String message) {
    if (message.equals(null)) {
        return Boolean.FALSE;
    }

    clientSock = socketDict.get(clientPort);
    try {
        logger.info("[NetworkNode] Sending: "+message+" sent through port: "+clientPort.toString());
        clientSock.send(message);
        return Boolean.TRUE;

    } catch (Exception e) {
        if (clientSock.getSocketChannel() != null) {
            clientSock.deleteConnection();
        }
        logger.debug("[NetworkNode] Send Failed: " + message + " not sent through port: " + clientPort.toString());
        return Boolean.FALSE;
    }
}

recv():

/**
 * Receives a message from the specified IP:port, if possible.
 *
 * @return String containing the received message.
 */

@Override
public String recv(String receivingPort) {
    clientSock = socketDict.get(receivingPort);
    try {
        response = clientSock.recv();
        response.trim();
        logger.info("[NetworkNode] Recv on port:"+receivingPort.toString()+response);
        return response;
    } catch (Exception e) {
        if (clientSock.getSocketChannel() != null) {
            clientSock.deleteConnection();
        }
        logger.debug("[NetworkNode] Recv Failed on port: " + receivingPort.toString());
        return "";
    }

}

这个send()和recv()函数所在的NetworkNode模块的完整代码是here,高可用性支持的完整包是here(如果需要的话)


共 (4) 个答案

  1. # 1 楼答案

    NetworkNode中存在多个问题。recv()方法:

    • 在解引用对象之前,应该检查null
    • 您不应该在String对象上调用toString。这是多余的
    • 在捕获和忽略异常时,应该小心。在这种情况下,您不需要将异常捕获为NioClient。recv()不会抛出任何错误。该方法应该在哪里抑制异常是另一个问题
    • 避免使用成员变量而不是局部变量。每个方法都需要声明局部变量。这是代码中许多地方的常见问题

    接收方法可重写如下:

    NioClient receivingSock = socketDict.get(receivingPort);
    if (receivingSock == null) {
        logger.debug("[NetworkNode] No receivingSock on receivingport: " + receivingPort);
        return "";
    }
    else {
        response = receivingSock.recv();
        if (response != null) {
            response.trim();
        }
        return response;
    }
    
  2. # 2 楼答案

    NetworkNode.recv()中引发的第一个空指针异常是因为clientSock从未初始化。无法检查第535行上的空比较,因为clientSock不存在,因此无法调用方法getSocketChannel()

    多个类缺少初始化所有变量的构造函数方法。这似乎是大多数问题的基础。确保也调用了所有init()preStart()方法。看起来大多数变量初始化都是在这些方法中进行的

  3. # 3 楼答案

    这段代码的问题是,当交换机向控制器发送一个新数据包时,receive()方法被调用,或者(比方说)处于活动状态

    这里,当第一个控制器接收到ICMP数据包时,它通过以下代码段向第二个控制器发送hello消息:

     hacontroller.send("127.0.0.1:4243", "mHelloWorld");
    

    但是,由于第二个控制器没有收到来自交换机的任何消息,它目前没有实现这段代码(receive()),并且没有看到:

    hacontroller.recv("127.0.0.1:4242");
    

    据我所知,这就是clientSock从未初始化的原因,所以我收到了这个错误

  4. # 4 楼答案

    从您发布的日志和您提供的Github存储库来看,clientSock似乎是null。第一个NullPointerException被抛出到第529行:

    response = clientSock.recv();
    

    被抓住了

    但是在catch块中,clientSock仍然是null,所以当您这样做时:

    if (clientSock.getSocketChannel() != null) {
    

    第二个NullPointerException被抛出(我们在日志中看到的那个),隐藏了之前抛出的那个

    你能调试你的代码来验证socketDict是否包含receivingPort吗?如果没有,请确保正确初始化

    此外,捕获Exception通常不是一个好主意,因为它太大了。如果可以的话,我建议你捕捉一个或多个更精确的异常。如果你这样做了,你会更容易地看到这个错误的来源