In
AbstractByteArraySerializer why we need this method?
protected void checkClosure(int bite) throws IOException {
if (bite < 0) {
logger.debug("Socket closed during message assembly");
throw new IOException("Socket closed during message assembly");
}
}
When asking questions like this, it's generally best to explain why you are asking it - like are you experiencing some problem that you are trying to understand.
TCP is a streaming protocol; we need some way to delimit a message from the stream, for example CRLF; that's what the (de)serializers do - serializers add structure to the stream, deserializers decode the messages from the stream.
We need to detect if the client closes the socket before a complete message is received.
If you wish the client to signal the end of the message by closing the socket, then you can use the ByteArrayRawSerializer.
Related
I am unable to get two users chatting to each other despite reducing the complexity and the potential code that could have caused the issue.
I am able to emit to all connected sockets so I have established it's not an issue in context of emit/on structure but rather; coming from the way i'm handling the private socket ids.
I have tried various versions of trying to send the private message to the correct socket id; I have tried older ways such as socket.to and the current way from the docs which is io.to(sockid).emit('event' message); all these variations have been unable to help me. I have consoled out the socket id I have on my Angular client side by printing console.log('THIS IS MY SOCKET '+this.socket.id) and comparing it to the value I have in Redis using redis-cli and they both match perfectly every time which doesn't give me too much to go on.
problem arises here:
if (res === 1) {
_active_users.get_client_key(recipient)
.then(socket_id => {
console.log('======='+io.sockets.name)
console.log('I am sending the message to: '+ recipient + 'and my socket id is'+ socket_id)
// socket.to(socket_id)socket.emit('incoming', "this is top secret"
io.of('/chat').to(socket_id).emit('incoming', "this is top secret")
})
.catch(error => {
console.log("COULD NOT RETRIEVE KEY: " + error)
})
Here is the link to the pastebin with more context:
https://pastebin.com/fYPJSnWW
The classes I import are essentially just setters and getters for handling the socket id you can think of them as just a worker class that handles Redis actions.
Expected: To allow two clients to communicate based on just their socket ids.
Actual:
am able to emit to all connected sockets and receive the expected results but the problem arises when trying to send to a specific socket id from a unknown reason.
Issue was coming from my front end.. I hope nobody has a headache like this! but here is what happened; when you're digging your own hole you often don't realise how deep you got yourself if you don't take the time to look around. I had two instances of the sockets. I instantiated both and used the one to connect and the other to send the message; which of course you cannnot do if you want things to work properly. So what I did was created only one instance of the socket in and and passed that ref of the socket around where I needed it which is ( sendMessage(username, socket) getMessage(socket)
ngOnInit(
this.socket = io.connect('localhost:3600',{
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax : 5000,
reconnectionAttempts: Infinity});
For examples like this:
https://bravenewmethod.com/2011/02/21/node-js-tls-client-example/
Or in my own code:
client = tls.connect(port, host, tlsOptions, function() {
}
client.on('end', function(data) {
}
When do these lifecycle methods get actually called? In the documentation, https://nodejs.org/api/tls.html, I don't see anything about it.
You need to be looking in the doc for the Net module for a TCP socket which a TLS socket inherits from. tls.TLSSocket is a subclass of net.Socket. This is a common issue with documentation for a class hierarchy where you don't realize that lots of things are documented in the base class documentation. In that doc, it says this for the end event:
Emitted when the other end of the socket sends a FIN packet, thus
ending the readable side of the socket.
By default (allowHalfOpen is false) the socket will send a FIN packet
back and destroy its file descriptor once it has written out its
pending write queue. However, if allowHalfOpen is set to true, the
socket will not automatically end() its writable side, allowing the
user to write arbitrary amounts of data. The user must call end()
explicitly to close the connection (i.e. sending a FIN packet back).
For the close event, that same doc says this:
Emitted once the socket is fully closed. The argument had_error is a
boolean which says if the socket was closed due to a transmission
error.
This means that the close event comes after the end event since the socket may be still at least partially open when the end event is received.
So, you will get end when the other side has told you it is no longer accepting data (receipt of FIN packet) and you will get close when the socket is now completely closed.
The tls.TLSSocket class is an instance of the net.Socket class. You can find additional information about the events and methods it has in that documentation (https://nodejs.org/api/net.html#net_class_net_socket). Most likely, net.Socket#end if I had to guess.
I wrote a simple flow for AMQP inbound messages with Json payloads, something like
IntegrationFlows
.from(Amqp.inboundGateway(connectionFactory, new Queue("qin"))
.errorChannel(Amqp.channel("dlx", connectionFactory))
)
.handle(new MessageTransformingHandler(m -> {
Object result = null;
try {
result = (...)
} catch (Exception e) {
throw new MessageTransformationException(m, e.getMessage());
}
(...)
}))
.transform(Transformers.toJson(...))
.handle(Amqp.outboundAdapter(new RabbitTemplate(connectionFactory))
.routingKey("qout"))
.get();
}
This works perfectly OK, except when there's errors! As it is now I do get the error in DLX but in content_type: application/x-java-serialized-object and it is required to be application/json.
I could do this by having the error channel specify 2 converters
.amqpMessageConverter(...)
.messageConverter(...)
but the problem is that I have to implement then myself which is not easy because I have to deal with converting messages to ampqmessages, plus the business objects, plues the error object and text, and so on...
So I was thinking if I couldn't have a adapter in front of the error channel that at least took care of message->amqpmessage conversion (hopefully the payloads as well).
I also tried having a errorHandler instead of a errorChannel but the problems are the same.
Any sugestion?
Thanks in advance.
EDITED
Many thanks for your reply. However I'm struggling with it. After many tries and errors, I finally think I understand the solution (to use a "intermediary" channel so I can handle the message before send it to Amqp?) but I still can't get it to work. I have now
.errorChannel(MessageChannels.direct("amqpErrorChannel").get())
and the a flow listening to that channel
#Bean
public IntegrationFlow errorFlow() {
return IntegrationFlows.from("amqpErrorChannel")
.handle(new MessageTransformingHandler(m ->(...)
but I still have a error
MessageDeliveryException: Dispatcher has no subscribers for channel
'amqpErrorChannel'.
Any pointers to what I'm doing wrong?
Cheers.
Yes, you can have .transform() or any other adapter in front of (Amqp.channel("dlx", connectionFactory). Actually .errorChannel() is just a hook to send error to the error handling flow. So, you can use there any simple Spring Integration channel (not an AMQP one) and build any complex error handling logic.
Correct, in the end of that flow you can send a result message (after a bunch of transformation, enrichment etc.) to the AMQP dlx, but for this purpose the simple one-way Amqp.outboundAdapter() would be enough.
To be honest Amqp.channel() is two-way and that really would be better that you have a subscriber for it. But your case is one-way, so you should use Amqp.outboundAdapter() there instead.
I have already written a request-method in java that sends a request to a simple Server. I have written this simple server and the Connection is based on sockets. When the server has the answer for the request, it will send it automatically to client. Now I want to write a new method that can behave as following:
if the server does not answer after a fixed period of time, then I send a new Request to the server using my request-method
My problem is to implement this idea. I am thinking in launching a thread, whenever the request-method is executed. If this thread does not hear something for fixed period of time, then the request method should be executed again. But how can I hear from the same socket used between that client and server?
I am also asking,if there is a simpler method that does not use threads
curently I am working on this idea
I am working on this idea:
1)send a request using my request-method
2)launch a thread for hearing from socket
3)If(no answer){ go to (1)}
else{
exit
}
I have some difficulties in step 3. How I can go to (1)
You may be able to accomplish this with a single thread using a SocketChannel and a Selector, see also these tutorials on SocketChannel and Selector. The gist of it is that you'll use long-polling on the Selector to let you know when your SocketChannel(s) are ready to read/write/etc using Selector#select(long timeout). (SocketChannel supports non-blocking, but from your problem description it sounds like things would be simpler using blocking)
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
Selector selector = Selector.open();
SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
// returns the number of channels ready after 5000ms; if you have
// multiple channels attached to the selector then you may prefer
// to iterate through the SelectionKeys
if(selector.select(5000) > 0) {
SocketChannel keyedChannel = (SocketChannel)key.channel();
// read/write the SocketChannel
} else {
// I think your best bet here is to close and reopen the Socket
// or to reinstantiate a new socket - depends on your Request method
}
I am working on this idea:
1)send a request using my request-method
2)launch a thread for hearing from socket
3)If(no answer) then go to (1)
I need to develop a netty based Client, that accepts messages from a Notification Server, and places these messages as Http Requests to another Server in real time.
I have already coded a working application which does this, but I need to add multi-threading to this.
At this point, I am getting confused on how to handle Netty Channels inside a multi-threaded program, as I am all loaded with the conventional approach of sockets and threads.
When I tried to separate the Netty requesting part into a method, It complains about the Channels not being closed.
Can anyone guide me how to handle this?
I would like to use ExecutionHandler and OrderedMemoryAwareThreadPoolExecutor, but I am really new into this.
Help with some examples would be a real favour at this time.
Thanks in advance.
Just add an ExecutionHandler to the ChannelPipeline. This will make sure that every ChannelUpstreamHandler which is added behind the ExecutionHandler will get executed in an extra thread and so does not block the worker-thread.
Have you looked at the example code on the Netty site? The TelnetServer looks to do what you are talking about. The factory creates new handlers whenever it gets a connection. Threads from the Executors will be used whenever there is a new connection. You could use any thread pool and executor there I suspect:
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), << change
Executors.newCachedThreadPool())); << change
// Configure the pipeline factory.
bootstrap.setPipelineFactory(new TelnetServerPipelineFactory());
// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(8080));
The TelnetServerHandler then handles the individual results.
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
// Cast to a String first.
// We know it is a String because we put some codec in TelnetPipelineFactory.
String request = (String) e.getMessage();
// Generate and write a response.
String response;
boolean close = false;
if (request.length() == 0) {
response = "Please type something.\r\n";
When the telnet is ready to close the connection it does this:
ChannelFuture future = e.getChannel().write(response);
if (close) {
future.addListener(ChannelFutureListener.CLOSE);
}