UDP 介面卡

本節描述如何配置和使用 UDP 介面卡。

出站 UDP 介面卡(XML 配置)

以下示例配置了一個 UDP 出站通道介面卡

<int-ip:udp-outbound-channel-adapter id="udpOut"
    host="somehost"
    port="11111"
    multicast="false"
    socket-customizer="udpCustomizer"
    channel="exampleChannel"/>
當將 multicast 設定為 true 時,您還應在 host 屬性中提供多播地址。

UDP 是一種高效但不穩定的協議。Spring Integration 添加了兩個屬性來提高可靠性:check-lengthacknowledge。當 check-length 設定為 true 時,介面卡會在訊息資料之前新增一個長度欄位(網路位元組序的四個位元組)。這使得接收方可以驗證接收到的資料包的長度。如果接收系統使用的緩衝區太短無法容納資料包,資料包可能會被截斷。長度頭提供了一種檢測此問題的方法。

從 4.3 版本開始,您可以將 port 設定為 0,在這種情況下,作業系統會選擇埠。在介面卡啟動且 isListening() 返回 true 後,可以透過呼叫 getPort() 來發現所選埠。

從 5.3.3 版本開始,您可以新增一個 SocketCustomizer bean 來修改建立後的 DatagramSocket(例如,呼叫 setTrafficClass(0x10))。

以下示例展示了一個出站通道介面卡,它為資料報包新增長度檢查

<int-ip:udp-outbound-channel-adapter id="udpOut"
    host="somehost"
    port="11111"
    multicast="false"
    check-length="true"
    channel="exampleChannel"/>
資料包的接收者也必須配置為期望實際資料之前有一個長度欄位。對於 Spring Integration UDP 入站通道介面卡,設定其 check-length 屬性即可。

第二個可靠性改進允許使用應用層確認協議。接收方必須在指定的時間內向傳送方傳送確認訊息。

以下示例展示了一個出站通道介面卡,它為資料報包新增長度檢查並等待確認

<int-ip:udp-outbound-channel-adapter id="udpOut"
    host="somehost"
    port="11111"
    multicast="false"
    check-length="true"
    acknowledge="true"
    ack-host="thishost"
    ack-port="22222"
    ack-timeout="10000"
    channel="exampleChannel"/>
acknowledge 設定為 true 意味著資料包的接收方可以解釋新增到資料包中的包含確認資料(主機和埠)的頭。最有可能的是,接收方是一個 Spring Integration 入站通道介面卡。
multicasttrue 時,另一個屬性 (min-acks-for-success) 指定在 ack-timeout 內必須收到多少個確認。

從 4.3 版本開始,您可以將 ackPort 設定為 0,在這種情況下,作業系統會選擇埠。

出站 UDP 介面卡(Java 配置)

以下示例展示瞭如何使用 Java 配置出站 UDP 介面卡

@Bean
@ServiceActivator(inputChannel = "udpOut")
public UnicastSendingMessageHandler handler() {
    return new UnicastSendingMessageHandler("localhost", 11111);
}

(對於多播,使用 MulticastSendingChannelAdapter)。

出站 UDP 介面卡(Java DSL 配置)

以下示例展示瞭如何使用 Java DSL 配置出站 UDP 介面卡

@Bean
public IntegrationFlow udpOutFlow() {
    return f -> f.handle(Udp.outboundAdapter("localhost", 1234)
                    .configureSocket(socket -> socket.setTrafficClass(0x10)))
                .get();
}

入站 UDP 介面卡(XML 配置)

以下示例展示瞭如何配置一個基本的單播入站 UDP 通道介面卡。

<int-ip:udp-inbound-channel-adapter id="udpReceiver"
    channel="udpOutChannel"
    port="11111"
    receive-buffer-size="500"
    multicast="false"
    socket-customizer="udpCustomizer"
    check-length="true"/>

以下示例展示瞭如何配置一個基本的多播入站 UDP 通道介面卡

<int-ip:udp-inbound-channel-adapter id="udpReceiver"
    channel="udpOutChannel"
    port="11111"
    receive-buffer-size="500"
    multicast="true"
    multicast-address="225.6.7.8"
    check-length="true"/>

預設情況下,不對入站資料包執行反向 DNS 查詢:在未配置 DNS 的環境中(例如 Docker 容器),這可能會導致連線延遲。要將 IP 地址轉換為用於訊息頭的 hostname,可以透過將 lookup-host 屬性設定為 true 來覆蓋預設行為。

從 5.3.3 版本開始,您可以新增一個 SocketCustomizer bean 來修改建立後的 DatagramSocket。它會用於接收 socket 以及為傳送確認建立的任何 socket。

入站 UDP 介面卡(Java 配置)

以下示例展示瞭如何使用 Java 配置入站 UDP 介面卡

@Bean
public UnicastReceivingChannelAdapter udpIn() {
    UnicastReceivingChannelAdapter adapter = new UnicastReceivingChannelAdapter(11111);
    adapter.setOutputChannelName("udpChannel");
    return adapter;
}

以下示例展示瞭如何使用 Java DSL 配置入站 UDP 介面卡

入站 UDP 介面卡(Java DSL 配置)

@Bean
public IntegrationFlow udpIn() {
    return IntegrationFlow.from(Udp.inboundAdapter(11111))
            .channel("udpChannel")
            .get();
}

伺服器監聽事件

從 5.0.2 版本開始,當入站介面卡啟動並開始監聽時,會發出 UdpServerListeningEvent 事件。當介面卡配置為監聽埠 0(意味著作業系統選擇埠)時,這非常有用。如果您需要在啟動連線到 socket 的其他程序之前等待,也可以使用它代替輪詢 isListening()

高階出站配置

<int-ip:udp-outbound-channel-adapter> (UnicastSendingMessageHandler) 具有 destination-expressionsocket-expression 選項。

您可以使用 destination-expression 作為硬編碼的 host-port 對的執行時替代方案,以根據 requestMessage(作為評估上下文的根物件)確定出站資料報包的目標地址。表示式必須評估為 URI、URI 風格的 String(參見 RFC-2396)或 SocketAddress。您還可以使用入站的 IpHeaders.PACKET_ADDRESS 頭作為此表示式。在框架中,當我們在 UnicastReceivingChannelAdapter 中接收資料報並將其轉換為訊息時,DatagramPacketMessageMapper 會填充此頭。頭的精確值是傳入資料報的 DatagramPacket.getSocketAddress() 的結果。

使用 socket-expression,出站通道介面卡可以使用(例如)入站通道介面卡的 socket 透過接收資料的同一埠傳送資料報。這在我們的應用程式作為 UDP 伺服器執行且客戶端在網路地址轉換 (NAT) 後面的場景中非常有用。此表示式必須評估為 DatagramSocketrequestMessage 用作評估上下文的根物件。您不能將 socket-expression 引數與 multicastacknowledge 引數一起使用。以下示例展示瞭如何配置一個 UDP 入站通道介面卡,其中包含一個將其轉換為大寫並使用 socket 的 transformer

<int-ip:udp-inbound-channel-adapter id="inbound" port="0" channel="in" />

<int:channel id="in" />

<int:transformer expression="new String(payload).toUpperCase()"
                       input-channel="in" output-channel="out"/>

<int:channel id="out" />

<int-ip:udp-outbound-channel-adapter id="outbound"
                        socket-expression="@inbound.socket"
                        destination-expression="headers['ip_packetAddress']"
                        channel="out" />

以下示例展示了使用 Java DSL 的等效配置

@Bean
public IntegrationFlow udpEchoUpcaseServer() {
    return IntegrationFlow.from(Udp.inboundAdapter(11111).id("udpIn"))
            .<byte[], String>transform(p -> new String(p).toUpperCase())
            .handle(Udp.outboundAdapter("headers['ip_packetAddress']")
                    .socketExpression("@udpIn.socket"))
            .get();
}