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-length
和 acknowledge
。當 check-length
設定為 true
時,适配器會在訊息資料前加上長度欄位(網路位元組順序的四個位元組)。這使接收端能夠驗證接收到的封包長度。如果接收系統使用的緩衝區太短而無法容納封包,則封包可能會被截斷。length
標頭提供了一種偵測此情況的機制。
從 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 輸入通道适配器。 |
當 multicast 為 true 時,額外的屬性 (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 位址轉換為主機名稱以用於訊息標頭,可以透過將 lookup-host
屬性設定為 true
來覆寫預設行為。
從 5.3.3 版開始,您可以新增 SocketCustomizer
bean 以在建立 DatagramSocket
後修改它。它會針對接收套接字以及為發送 ack 建立的任何套接字調用。
輸入 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
時,這非常有用,這表示作業系統會選擇埠。如果您需要在啟動將連線到套接字的其他程序之前等待,也可以使用它來代替輪詢 isListening()
。
進階輸出設定
<int-ip:udp-outbound-channel-adapter>
(UnicastSendingMessageHandler
) 具有 destination-expression
和 socket-expression
選項。
您可以使用 destination-expression
作為硬編碼 host
-port
對的執行階段替代方案,以針對 requestMessage
(使用評估內容的根物件)判斷輸出資料包的目的地位址。運算式必須評估為 URI
、URI 樣式的 String
(請參閱 RFC-2396)或 SocketAddress
。您也可以針對此運算式使用輸入 IpHeaders.PACKET_ADDRESS
標頭。在框架中,當我們在 UnicastReceivingChannelAdapter
中接收資料包並將其轉換為訊息時,DatagramPacketMessageMapper
會填入此標頭。標頭值正是傳入資料包的 DatagramPacket.getSocketAddress()
的結果。
使用 socket-expression
,輸出通道适配器可以使用(例如)輸入通道适配器套接字,透過接收資料包的相同埠發送資料包。這在我們的應用程式作為 UDP 伺服器且用戶端在網路位址轉換 (NAT) 後方運作的情況下很有用。此運算式必須評估為 DatagramSocket
。requestMessage
用作評估內容的根物件。您無法將 socket-expression
參數與 multicast
和 acknowledge
參數一起使用。以下範例顯示如何設定具有轉換器的 UDP 輸入通道适配器,該轉換器轉換為大寫並使用套接字
<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();
}