How to set SO_REUSEADDR in a TCP Outbound Adapter? - spring

I have several TCP/IP Outbound Adapters to send Messages to connecting clients. The TCP/IP protocol of communication requires the socket flags to be set: TCP_NODELAY, SO_REUSEADDR, and SO_KEEPALIVE.
#Override
public void start(String context, int port) {
TcpServerConnectionFactorySpec server = Tcp.netServer(port)
.id(context)
.soTcpNoDelay(true)
.soKeepAlive(true)
.serializer(new ByteArrayLengthHeaderSerializer())
;
IntegrationFlow flow = f -> f.handle(Tcp.outboundAdapter(server));
this.registrations.put(context, flowContext.registration(flow).register());
}
How do I set the socket's SO_REUSEADDR flag to TRUE?

Implement a custom TcpSocketSupport...
public class MySocketSupport extends DefaultTcpSocketSupport {
#Override
public void postProcessServerSocket(ServerSocket serverSocket) {
...
}
}
then...
.tcpSocketSupport(new MySocketSupport())

Related

Spring Integration - Multicast UDP message not updating

I try to listen periodic udp message with Multicast ip with spring integration, but my code get the same udp message all the time even if the udp message updated. When I stop my program and restart it, the message updates.
Here is my config config.java:
#Bean
public IntegrationFlow udpIn() {
return IntegrationFlows.from(Udp.inboundMulticastAdapter(16343, "239.0.12.1"))
.channel("inboundChannel")
.get();
}
and here is the method handle messages service.java:
#ServiceActivator(inputChannel = "inboundChannel")
public void handleMessage(Message message) {
log.info("message.getPayload());
byte[] values = (byte[]) message.getPayload();
//some irrelevant code
}
where is wrong about the code?
Thanks...

How do I throttle the amount of data sent to Stomp queue (handling websockets) so that I can guarantee that I don't overflow the buffer?

I have two Java processes and I am connecting them using a websocket in spring boot. One process acts as the client and connects like this:
List<Transport> transports = new ArrayList<Transport>(1);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
WebSocketClient client = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(client);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSessionHandler firstSessionHandler = new MyStompSessionHandler("Philip");
stompClient.connect("ws://localhost:8080/chat", firstSessionHandler);
The session handler extends StompSessionHandlerAdapter and provides these methods (I am subscribing by username so each client can receive its own messages):
#Override
public void afterConnected(
StompSession session, StompHeaders connectedHeaders) {
session.subscribe("/user/" + userName + "/reply", this);
session.send("/app/chat", getSampleMessage());
}
#Override
public void handleFrame(StompHeaders headers, Object payload) {
Message msg = (Message) payload;
// etc.....
}
On the server side I have a Controller exposed and I am writing data by calling the endpoint from a worker thread.
#Autowired
private SimpMessagingTemplate template;
#MessageMapping("/chat")
public void send(
Message message)
throws Exception {
template.convertAndSendToUser(message.getFrom(),
"/reply",
message);
}
In the websocket config I am overriding the method to set the limits:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/user");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(500 * 1024);
registration.setSendBufferSizeLimit(1024 * 1024);
registration.setSendTimeLimit(20000);
}
My question is this, if the load on the server gets high enough and I overrun the limit, the websocket fails catastrophically, and I want to avoid this. What I would like to do is for the controller to have the ability to ask the message broker "will this message fit in the buffer?", so that I can throttle to stay under the limit. I searched the API documentation but I don't see any way of doing that. Are there any other obvious solutions that I am missing?
Thanks.
Actually I found a solution, so if anyone is interested, here it is.
On the server side configuration of the websockets I installed an Interceptor on the Outbound Channel (this is part of the API), which is called after each send from the embedded broker.
So I know how much is coming in, which I keep track of in my Controller class and I know how much is going out through the Interceptor that I installed, and this allows me to always stay under the limit.
The controller, before accepting any new messages to be queued up for the broker first determines if enough room is available and if not queues up the message in external storage until such time as room becomes available.

Spring TCP messaging server with whitelist address

I am using Spring Integration's TcpNetServerConnectionFactory and TcpInboundGateway to receive TCP messages. Everything is working as expected, but I was wondering if there is any way to implement address whitelisting? (Basically I want to allow a specified address and reject connections from others.) Maybe there is a way to add a callback to accept/reject when a connection is made, I couldn't find any mention in the docs or samples.
Create a custom TcpNetConnectionSupport (subclass DefaultTcpNetConnectionSupport and override createNewConnection()).
I think you should be able to close the socket there.
Inject it into the server connection factory.
See Advanced Techniques.
EDIT
It was added in Spring Integration 5...
#SpringBootApplication
public class So48951046Application {
public static void main(String[] args) {
SpringApplication.run(So48951046Application.class, args).close();
}
#Bean
public ApplicationRunner runner() {
return args -> {
Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234);
Thread.sleep(10_000);
socket = SocketFactory.getDefault().createSocket("localhost", 1234);
Thread.sleep(10_000);
};
}
#Bean
public TcpNetServerConnectionFactory server() {
TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(1234);
server.setTcpNetConnectionSupport(new DefaultTcpNetConnectionSupport() {
#Override
public TcpNetConnection createNewConnection(Socket socket, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName)
throws Exception {
TcpNetConnection conn = super.createNewConnection(socket, server, lookupHost, applicationEventPublisher, connectionFactoryName);
if (conn.getHostAddress().contains("127")) {
conn.close();
}
return conn;
}
});
return server;
}
#Bean
public TcpReceivingChannelAdapter adapter() {
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(server());
adapter.setOutputChannel(new NullChannel());
return adapter;
}
}
and
: server, port=1234 Listening
: Started So48951046Application in 0.907 seconds (JVM running for 1.354)
: Accepted connection from 127.0.0.1
: New connection localhost:63624:1234:b558c7ca-f209-41b1-b958-7d9844f4d478
: server: Added new connection: localhost:63624:1234:b558c7ca-f209-41b1-b958-7d9844f4d478
: localhost:63624:1234:b558c7ca-f209-41b1-b958-7d9844f4d478 Reading...
: server: Removed closed connection: localhost:63624:1234:b558c7ca-f209-41b1-b958-7d9844f4d478
: Read exception localhost:63624:1234:b558c7ca-f209-41b1-b958-7d9844f4d478 SocketException:Socket is closed
: Accepted connection from 127.0.0.1
: New connection localhost:63625:1234:50c7b774-522a-4c43-b111-555e76611a33
: server: Added new connection: localhost:63625:1234:50c7b774-522a-4c43-b111-555e76611a33
: server: Removed closed connection: localhost:63625:1234:50c7b774-522a-4c43-b111-555e76611a33
: localhost:63625:1234:50c7b774-522a-4c43-b111-555e76611a33 Reading...
: Read exception localhost:63625:1234:50c7b774-522a-4c43-b111-555e76611a33 SocketException:Socket is closed

Error creating WebSocket connection using AsyncHttpClient behind Squid Proxy

Library in use:
AsyncHtpClient Library:
Version : 1.9.32
Location: https://github.com/AsyncHttpClient/async-http-client
Netty Version : 3.10.3.Final
Proxy: Squid Proxy
I am trying to create a websocket connection using AsyncHttpClinet library. It works fine when using without the proxy.
But when I start a proxy and pass in the Host, port, username and password , I am unable to create a websocket connection.
It get a stack trace which says Invalid Status Code 400:
Caused by: java.lang.IllegalStateException: Invalid Status Code 400
at com.ning.http.client.ws.WebSocketUpgradeHandler.onCompleted(WebSocketUpgradeHandler.java:76)
at com.ning.http.client.ws.WebSocketUpgradeHandler.onCompleted(WebSocketUpgradeHandler.java:29)
at com.ning.http.client.providers.netty.future.NettyResponseFuture.getContent(NettyResponseFuture.java:177)
at com.ning.http.client.providers.netty.future.NettyResponseFuture.done(NettyResponseFuture.java:214)
... 35 more
I am setting the proxy object like this:
ProxyServer ps = new ProxyServer("host-name",portNo,"user_name","password");
AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setProxyServer(ps).build();
WebSocket websocket = c.prepareGet(url)
.execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(
new WebSocketTextListener() {
#Override
public void onMessage(String message) {
}
#Override
public void onFragment(String s, boolean b) {
}
#Override
public void onOpen(WebSocket websocket) {
}
#Override
public void onClose(WebSocket websocket) {
}
#Override
public void onError(Throwable t) {
}
}
).build()
).get();
Are there any other steps to configure a proxy for websocket connections?
I have also tried configuring the ProxyServer object like this:
ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS,"host-name",portNo,"user_name","password");

How to stop Spark Streaming context when the network connection (TCP IP) is closed?

In other words Instead of setting 'duration' in Spark streaming context to a value, I want to set it to (socket close time - socket open time)
You could use the StreamingListner interface to listen for the receiver being disconencted, and then shutdown the streaming context.
This is used as
// define listener
class MyListener extends StreamingListener {
override def onReceiverStopped(...) {
streamingContext.stop()
}
}
// attach listener
streamingContext. addStreamingListener(new MyListener())
By doing ssc.stop() in streaming listener, when ur streaming got error or teriminated this function will trigger to stop. There's another triggers like when the batch started,finished,etc.
ssc.addStreamingListener(new StreamingListener() {
#Override
public void onReceiverError(StreamingListenerReceiverError receiverError) {
System.out.println("Do what u want");
ssc.stop();
}
#Override
public void onReceiverStopped(StreamingListenerReceiverStopped receiverStopped) {
System.out.println("Do what u want");
ssc.stop(true,true);
}
}
ssc.start();

Resources