I am a beginner learning Camel and trying to run netty4 on camel using apache blueprint.
I am creating a TCP server using netty :
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="timerToLog">
<from uri="netty4:tcp://localhost:5150"/>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
</camelContext>
Everything works fine when I run camel using mvn:
[ Blueprint Extender: 1] TCPNettyServerBootstrapFactory INFO ServerBootstrap binding to localhost:5150
[ Blueprint Extender: 1] NettyConsumer INFO Netty consumer bound to: localhost:5150
[ Blueprint Extender: 1] BlueprintCamelContext INFO Route: timerToLog started and consuming from: Endpoint[tcp://localhost:5150]
I connect to the tcp server using and send data using Hercules ( even tried windows telnet ) and as soon as I send a "Hello" ascii text, the connection gets closed with the following error:
[d #0 - NettyEventExecutorGroup] NettyConsumer WARN Closing channel as an exception was thrown from Netty. Caused by: [io.netty.hand
ler.codec.TooLongFrameException - Adjusted frame length exceeds 1048576: 1212501072 - discarded]
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 1212501072 - discarded
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:499)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403) ...
I am only sending a "Hello" over the socket and still it says frame length exceeded.. !
I know am missing something very basic. Please bear with me and help :)
According to the Camel Netty4 Component documentation if the textline parameter of the the url is NULL then it installs and uses a default encoder/decoder. This is the equivalent of using textline=false which is the default behavior.
In your example you have this for the netty4 component:
<from uri="netty4:tcp://localhost:5150"/>
Thus you are using the default encoder/decoders which probably is not a text line based encoder/decoder. YOu can probably find which is the default encoder in the documentation but I think you probably can learn more than me by finding that information.
Remember that Netty uses the concept of encoders and decoders to send/receive data to and from clients and servers. These decoders define how Netty should read the raw data from the socket. If you are unfamiliar with this there is tons of documentation on Netty available.
Lets look at how to implement a simple text line based protocol encoder/decoder like you want to achieve.
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="timerToLog">
<from uri="netty4:tcp://localhost:5150?textline=true"/>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
All you were missing was the encoder bit.
Related
I am trying to connect to streamLabs socket API using Java. The API url is
https://sockets.streamlabs.com?token=<socketToken>
This doesnt work because Java expects the socket to be ws://.... When I change it to "ws" format it gives a connection timeout.
Am I missing something? Is this not actually a websocket, if not how would it work?
Here is a link to their documentation: https://streamlabs.readme.io/docs/socket-api
More info: I have tried with both org.asynchttpclient.ws.WebSocket and javax.websocket neither are working
Solved using SocketIo
<dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>1.0.0</version>
</dependency>
Their socket documentation is definitely lacking, their actual websocket url you will be connecting to is
wss://sockets.streamlabs.com/socket.io/?token=<your_socket_api_token>&transport=websocket
Additionally, since it's not really mentioned anywhere, they use an integer, prepended to their messages, as a message type indicator.
0 is the init message type, containing heartbeat interval and timeout
40 is the ping message you will be sending and receiving
41 is invalid token message you will get after connecting with an invalid token
42 will be the actual streamlabs event messages you will be getting
At least that's what I've gathered so far from poking around a bit.
We are using Spring integration 4.1.3.
Implemented the client using tcp-outbound-gateway.
A tcp rset packet was received from the server during the request and an exception occurred.
What is the reason?
Thank you.
// interface
public interface TcpSendGateway {
public byte[] send(String text);
}
// send
byte[] response = sendGateway.send(request);
<int:gateway id="gw"
service-interface="com.mainpay.service.TcpSendGateway"
default-request-channel="input"
default-reply-channel="reply"/>
<int-tcp:tcp-connection-factory id="client"
type="client"
host="#{prop['app.cultureland.host']}"
port="#{prop['app.cultureland.port']}"
so-timeout="10000"
single-use="false"
so-keep-alive="true"
/>
<int:channel id="input" />
<int-tcp:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="reply"
connection-factory="client"
request-timeout="10000"
reply-timeout="10000"
/>
<int:channel id="reply" datatype="java.lang.String" />
ERROR LOG
▶ 17.09.29 17:07:37 [pool-2-thread-2] ERROR o.s.i.i.t.c.TcpNetConnection - Read exception 211.59.10.133:7611:51503:d2ec0199-fd15-49c0-bd99-0d864eb2145b SocketException:Connection reset
▶ 17.09.29 17:07:39 [http-nio-19900-exec-5] ERROR o.s.i.ip.tcp.TcpOutboundGateway - Tcp Gateway exception
org.springframework.messaging.MessagingException: Exception while awaiting reply; nested exception is java.net.SocketException: Connection reset
at org.springframework.integration.ip.tcp.TcpOutboundGateway$AsyncReply.getReply(TcpOutboundGateway.java:288)
wireshark log
enter image description here
I think you should be sure that your client and server are agreed with the (de)serialization protocol. See Reference Manual for more info:
TCP is a streaming protocol; this means that some structure has to be provided to data transported over TCP, so the receiver can demarcate the data into discrete messages. Connection factories are configured to use (de)serializers to convert between the message payload and the bits that are sent over TCP.
The default one is the ByteArrayCrLfSerializer which deals with the \r\n message delimiter.
So, your client may receive the package but since it doesn't meet the proper delimiter it fails waiting for the reply.
java.net.SocketException: Connection reset
Means the server forced the socket closed (RST) for some reason. You need to look at the server logs.
Perhaps it's not expecting the default wire format (text terminated by CRLF - 0x0d0a).
I have the spring integration XML config with following bean
<int-ip:tcp-outbound-channel-adapter id="outboundClient"
channel="input"
connection-factory="client"/>
I thought the equivalent in java config would be
#ServiceActivator(inputChannel = "input", requiresReply = "true")
public TcpSendingMessageHandler outboundClient() {
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(clientConnectionFactory());
tcpSendingMessageHandler.setRetryInterval(10000);
tcpSendingMessageHandler.setClientMode(true);
return tcpSendingMessageHandler;
}
However, in the log, I see
TcpListener exiting - no listener and not single use
and I can't receive the reply from server.
Any help is appreciated
The TcpSendingMessageHandler is for one-way usage - just for sending messages to the TCP socket.
So, your config looks good and seems for me it should work.
TcpListener exiting - no listener and not single use
Is just DEBUG message from the TcpNetConnection which indicates that your component is one-way.
Therefore it is normal that you can't receive a reply from the server. Because you only send message to there.
To have request/reply scenarios consider to use TcpOutboundGateway.
I'm trying to configure Spring on the server side to open a socket, listen for connections and take the incoming stream (converting to String).
But I cannot find any working examples on how to just create such an incoming tcp connection. This is what I have (taken from an incomplete example):
<int-ip:tcp-connection-factory id="cfServer"
type="server"
port="8080"
using-nio="true"
single-use="true" />
<int-ip:tcp-inbound-channel-adapter id="inboundServer"
channel="loop"
connection-factory="server"/>
<int:channel id="loop"/>
Well, but how do I continue? How can I acutally bind these adapters to a backing class? And what do these classes have to look like?
Subscribe something to the loop channel, e.g. a <service-activator/>.
See the tcp-client-server sample
I am trying to setup a C client to talk to a hornetq jms server. I am using its STOMP acceptor with libstomp on the C side.
My C client code is just this example from the libstomp page verbatim with the passphrase and destination queue name changed (to a valid queue that can be accessed from a java client).
Here's what I get when I run it:
Connecting......OK
Sending connect message.OK
Reading Response.Response: CONNECTED,
OK
Sending Subscribe.OK
Sending Message.OK
Reading Response.Response: ERROR, org.hornetq.core.protocol.stomp.StompException: Client must set destination or id head
er to a SUBSCRIBE command
at org.hornetq.core.protocol.stomp.StompProtocolManager.onSubscribe(StompProtocolManager.java: 339)
at org.hornetq.core.protocol.stomp.StompProtocolManager.handleBuffer(StompProtocolManager.java:196)
at org.hornetq.core.protocol.stomp.StompConnection.bufferReceived(StompConnection.java:279)
at org.hornetq.core.remoting.server.impl.RemotingServiceImpl$DelegatingBufferHandler.bufferRec eived(RemotingServ
iceImpl.java:512)
at org.hornetq.core.remoting.impl.netty.HornetQChannelHandler.messageReceived(HornetQChannelHa ndler.java:73)
at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:100)
at org.jboss.netty.channel.StaticChannelPipeline.sendUpstream(StaticChannelPipeline.java:372)
at org.jboss.netty.channel.StaticChannelPipeline.sendUpstream(StaticChannelPipeline.java:367)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261)
at org.jboss.netty.channel.socket.oio.OioWorker.run(OioWorker.java:100)
at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:44)
at org.jboss.netty.util.VirtualExecutorService$ChildExecutorRunnable.run(VirtualExecutorServic e.java:181)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
OK
Sending Disconnect.OK
Disconnecting...OK
In short - I get this exception from the server:
ERROR, org.hornetq.core.protocol.stomp.StompException: Client must set destination or id header to a SUBSCRIBE command
On line 92 of the example, we set the destination:
apr_hash_set(frame.headers, "destination", APR_HASH_KEY_STRING, "/queue/FOO.BAR");
Despite this, when the message gets to the server and it parses the headers, I get a map ation -> /queue/FOO.BAR, but it's looking for a destination key. I have confirmed that the client is adding the correct map entry to the headers and it is not corrupted all the way through to sending it to the network.
Any pointers as to what might be wrong?
P.S. hornetq is 2.2.9.Final, libstomp is the latest revision from svn (rev 90 - http://svn.codehaus.org/stomp/trunk/c/), and it was compiled with apr 1.4.6; all running on Win-7
2.2.9 is a pretty old HornetQ release. You should retry with 2.2.14, or with the latest 2.3.beta. I just looked at the code in git for HornetQ master, the destination is being handled
See onSubscribe() at https://github.com/hornetq/hornetq/blob/master/hornetq-server/src/main/java/org/hornetq/core/protocol/stomp/VersionedStompFrameHandler.java#L254
FWIW, in HornetQ a dot . is used as divisor for destinations (your code is using a slash /). The STOMP protocol leaves this as an implementation dependent convention.