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 時,您還應該在主機屬性中提供多播地址。 |
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 入站通道介面卡。 |
當多播為 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 後對其進行修改。它適用於接收套接字和為傳送確認而建立的任何套接字。
入站 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();
}