packet loss socket io - websocket

I encountered such a problem. When online, about 1000 people start having problems with socket io. Some messages are not received to the recipients. The loads are approximately the following: a message is sent 2 times per second to all clients. At the moment there is a cluster of 6 servers, all clients are evenly distributed across the socket io servers, but there are still losses. On the server side, I use io + redis socket. PHP sends a message to redis, and then the server on node js reads it and sends it to all clients on sockets. Server Code:
redis.psubscribe('*');
redis.on('pmessage', (subscribed, channel, message) => {
message = JSON.parse(message);
io.to(channel).emit(channel, message.data);
});
/** SOCKET.IO **/
io.on('connection', socket => {
socket.on('subscribe', data => {
socket.join(data.channel)
});
});
What would you advise? Can use redis + socket io not the best option? All traffic goes through cloudflare. Can there be losses because of this?

Related

How to prevent buffering/latency with PUB/SUB?

I'm sending video as a sequence of images (equals zmq messages) but sometimes, perhaps when the network is slow, they are received at a slower rate than they're sent and a growing latency appears, seemingly up to about a minute of video or 100s of images or megabytes of data. It usually clears itself eventually with the subscriber receiving messages at a faster rate than the publisher sends.
Instead, I want it to discard missed messages the same way it's supposed to if the subscriber is too slow recving them. I hoped zmq.CONFLATE=1 would do this but it doesn't. How then? I suspect they're being buffered at the publisher, which is not supposed to have any zmq buffer, or in the network stack somehow.
Simplified server code
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:12345")
camera = PiCamera()
stream = io.BytesIO()
for _ in camera.capture_continuous(stream, 'jpeg', use_video_port=True):
stream.truncate()
stream.seek(0)
socket.send(stream.read())
stream.seek(0)
Simplified client code
# Initialization
self.context = zmq.Context()
self.video_socket = self.context.socket(zmq.SUB)
self.video_socket.setsockopt(zmq.CONFLATE, 1)
self.video_socket.setsockopt(zmq.SUBSCRIBE, b"")
self.video_socket.connect("tcp://" + ip_address + ":12345")
def get_image(self):
# Receive the latest image
poll_result = self.video_socket.poll(timeout=0)
if poll_result == zmq.POLLIN:
return self.video_socket.recv()
else:
return None
The publisher is on a Raspberry Pi and the subscriber is on Windows.
I am not sure which version of python zmq you are using but based on the underlying c++ libzmq you need to:
Set the ZMQ_SNDHWM socket option on the server socket
Set the ZMQ_RCVHWM socket option on the client socket.
These options limit the number of messages to queue per completed connection in the case of pub/sub. If the queue grows larger than the HWM (high water mark) the messages will be discarded.
Also turn off conflate as that will interfere with these options.
Also set zmq.CONFLATE=1 on the server to keep only the latest message in the send queue.
Before binding the server socket
socket.setsockopt(zmq.CONFLATE, 1)
For some reason I mistakenly thought the PUB socket didn't have a send queue but it does.

How many WebSocket connection can be created on Client Side

I have started to learn web sockets. It is must learn technology in today's time.
But i am curious to learn more about it. My basic question is How many WebSocket connection can be created on Client Side.
My Typically Application is html UI based and on the server i have rest based services. I need to track whether
Session timeout has happed or not
Whether Connection to the server is lost or not ? A kind of pooling program to check with connections is alive or not.
So I am creating 2 websocket objects on client and different url for them.
I hope i have implemented it correctly ?
Basically Browser closes the old websocket connection once you opened to new connection to SAME URL(ws://127.0.0.1:8080/WebSocket-context-root/getResource). You can keep small hack like "ws://127.0.0.1:8080/WebSocket-context-root/getResource/"+k. where k is any number/any random string. On server side just ignore the path variable k.
In this way you can open many number of connection at same time. Browser restriction of max-number-connection per domain is not applying here (Tested on Firefox). I tried max 25 parallel connections.
You can use websocket.readyState to check the status of the web socket connection.
onclose Event of the Web socket have reason code for closed connection.
User below code to test number of active connections.
var x=0
var intervalID = setInterval(function () {
websocket = new WebSocket("ws://127.0.0.1:8080/WebSocketApi/web/chat/"+x);
websocket.onopen = function (evt) {
console.log('open')
}
websocket.onmessage = function (evt) {
console.log('msg');
}
websocket.onclose= function (evt) {
console.log('closed');
}
if (++x === 15) {
window.clearInterval(intervalID);
}
}, 1);

TCP Communicator Application?

I am looking for software to help debug client/server software.
I am looking for an application where I can simply connect to a remote host on a given port and send it bytes of data and observe the responses.
Is there such software existing?
Use netcat. There are many different implementations. This is the manual for BSD's netcat.
nodejs do have an high level tcp api you can use to create a 5lines script that wee do the job for you
var net= require('net');
var sock = net.connect(1234, '127.0.0.1', function(){
sock.write(new Buffer("some binary data here"));
sock.write(new Buffer([0,1,2])); // 3 more bytes
sock.on("data", function(buffer) {
console.log("Server response is ", buffer); // display raw response buffer
})
});

socket.io - How to broadcast a message to all open sockets

I would like to broadcast a message to all open sockets as a result of a non-socket related event, e.g. as a result of a timeout. How do I do this? Should I keep an array of all open sockets and send them a message one by one? Is there a better way?
Note: The broadcasting example in socket.io guide sends a broadcast message in response to a socket connection, so it has a handle to a socket. Even then it says
Broadcasting means sending a message to everyone else except for the socket that starts it.
Edit
To clarify my question - I want to "send a message" to all open sockets. This action is NOT triggered by any socket, so there is no "this socket". For example, some business logic on the server decides that an order is now executed. This information needs to be sent to all open sockets. What's the best way to do this? (This is not "broadcasting" as socket.io defines it.)
So basically you need to get all connected clients to your socket
var clients = io.sockets.clients(); // This returns an array with all connected clients
for ( i = 0; i < clients.length; i++ ) {
clients[i].emit('event', { data: 'message' });
}
This will emit to all of your connected clients.
socket.broadcast.emit('event name', { data : 'your data' });
It will broadcast to all open sockets, except this socket.

TCP socket stops receiving data until closed

I have a really weird problem that is driving me crazy.
I have a Ruby server and a Flash client (Action Script 3). It's a multiplayer game.
The problem is that everything is working perfect and then, suddenly, a random player stops receiving data. When the server closes the connection because of inactivity, about 20-60 seconds later, the client receives all the buffered data.
The client uses XMLsocket for retrieving data, so the way the client receives data is not the problem.
socket.addEventListener(Event.CONNECT, connectHandler);
function connectHandler(event)
{
sendData(sess);
}
function sendData(dat)
{
trace("SEND: " + dat);
addDebugData("SEND: " + dat)
if (socket.connected) {
socket.send(dat);
} else {
addDebugData("SOCKET NOT CONNECTED")
}
}
socket.addEventListener(DataEvent.DATA, dataHandler);
function dataHandler(e:DataEvent) {
var data:String = e.data;
workData(data);
}
The server flushes data after every write, so is not a flushing problem:
sock.write(data + DATAEOF)
sock.flush()
DATAEOF is null char, so the client parses the string.
When the server accepts a new socket, it sets sync to true, to autoflush, and TCP_NODELAY to true too:
newsock = serverSocket.accept
newsock.sync = true
newsock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
This is my research:
Info: I was dumping netstat data to a file each second.
When the client stops receiving data, netstat shows that socket status is still ESTABLISHED.
Some seconds after that, send-queue grows accordingly to data sent.
tcpflow shows that packets are sent 2 times.
When the server closes the socket, socket status changes to FIN_WAIT1, as expected. Then, tcpflow shows that all buffered data is sent to the client, but the client don't receives data. some seconds after that, connection dissapears from netstat and tcpflow shows that the same data is sent again, but this time the client receives the data so starts sending data to the server and the server receives it. But it's too late... server has closed connection.
I don't think it's an OS/network problem, because I've changed from a VPS located in Spain to Amazon EC2 located in Ireland and the problem still remains.
I don't think it's a client network problem too, because this occurs dozens of times per day, and the average quantity of online users is about 45-55, with about 400 unique users a day, so the ratio is extremely high.
EDIT:
I've done more research. I've changed the server to C++.
When a client stops sending data, after a while the server receives a "Connection reset by peer" error. In that moment, tcpdump shows me that the client sent a RST packet, this could be because the client closed the connection and the server tried to read, but... why the client closed the connection? I think the answer is that the client is not the one closing the connection, is the kernel. Here is some info: http://scie.nti.st/2008/3/14/amazon-s3-and-connection-reset-by-peer
Basically, as I understand it, Linux kernels 2.6.17+ increased the maximum size of the TCP window/buffer, and this started to cause other gear to wig out, if it couldn’t handle sufficiently large TCP windows. The gear would reset the connection, and we see this as a “Connection reset by peer” message.
I've followed the steps and now it seems that the server is closing connections only when the client losses its connection to internet.
I'm going to add this as an answer so people know a bit mroe about this.
I think the answer is that the kernel is the one closing the connection. Here is some info: http://scie.nti.st/2008/3/14/amazon-s3-and-connection-reset-by-peer
Basically, as I understand it, Linux kernels 2.6.17+ increased the maximum size of the TCP window/buffer, and this started to cause other gear to wig out, if it couldn’t handle sufficiently large TCP windows. The gear would reset the connection, and we see this as a “Connection reset by peer” message.
I've followed the steps and now it seems that the server is closing connections only when the client losses its connection to internet.

Resources