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
時,介面卡會在訊息資料之前新增一個長度欄位(網路位元組序的四個位元組)。這使得接收方可以驗證接收到的資料包的長度。如果接收系統使用的緩衝區太短無法容納資料包,資料包可能會被截斷。長度頭提供了一種檢測此問題的方法。
從 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 地址轉換為用於訊息頭的 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-expression
和 socket-expression
選項。
您可以使用 destination-expression
作為硬編碼的 host-port 對的執行時替代方案,以根據 requestMessage
(作為評估上下文的根物件)確定出站資料報包的目標地址。表示式必須評估為 URI
、URI 風格的 String
(參見 RFC-2396)或 SocketAddress
。您還可以使用入站的 IpHeaders.PACKET_ADDRESS
頭作為此表示式。在框架中,當我們在 UnicastReceivingChannelAdapter
中接收資料報並將其轉換為訊息時,DatagramPacketMessageMapper
會填充此頭。頭的精確值是傳入資料報的 DatagramPacket.getSocketAddress()
的結果。
使用 socket-expression
,出站通道介面卡可以使用(例如)入站通道介面卡的 socket 透過接收資料的同一埠傳送資料報。這在我們的應用程式作為 UDP 伺服器執行且客戶端在網路地址轉換 (NAT) 後面的場景中非常有用。此表示式必須評估為 DatagramSocket
。requestMessage
用作評估上下文的根物件。您不能將 socket-expression
引數與 multicast
和 acknowledge
引數一起使用。以下示例展示瞭如何配置一個 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();
}