4

I am using Socket.io to stream live tweets to my users using Twitter's Streaming API (my implementation is more or less based on this tutorial).

The problem is that every time a connection event is fired by Socket.io the newly connected client causes every other client connected to the server to cease updating. While it would take too long to go through all the hacks that I tried, I will say that I played with it enough that I believe the problem is caused by Socket.io's multiplexing of the connections from multiple clients (enabled by default) as a performance boost to allow multiple clients or connections to share the same underlying socket. In short, I believe this to be the case because I don't think it would be possible for new connections to affect older connections in this manner if not for the connection multiplexing. In other words, if a new, independent connection with its own underlying (TCP) socket were created every time a client connected it would be impossible for this to occur since one connection would know nothing about the other and therefore couldn't affect any other client's state as is currently happening. This also leads me to believe that simply disabling the multiplexing functionality would be the simplest way to get around this problem since I am not concerned about scaling because Node.js already handles all the concurrency I'm likely to need to handle very adequately.

I have gone through Socket.io's documentation but could not see where the ability to "demultiplex" the connections is exposed via the API, so if anyone knows how to do this I'd create appreciate your response.

My code below is pretty standard and simple. But just to be clear, the issue is that whenever a new client connects to Socket.io every other client stops receiving new tweets and updates are no longer pushed to the older client unless I refresh the browser in which case the newly refreshed client will begin to update and receive fresh tweets again, but the other still connected clients will then stop updating.

Server-side Code:

// Code also uses ntwitter (https://github.com/AvianFlu/ntwitter) as an abstraction over Twitter's Streaming API
io.sockets.on('connection', function (socket) {
  tweet.stream('statuses/filter', { track : 'new orleans' }, function (stream) { 
    stream.on('data', function (data) {
      // The following lines simply pre-process data sent from Twitter so junk isn't
      // unnecessarily sent to the client.
      if (data.user) {
         tweets = {
         text  : data.text,
         image : data.user.profile_image_url,
         user  : data.user.name
         };
         var t = JSON.stringify(tweets);
         console.log(t);
         socket.send(t);
      }  
    });
  });
});

Client-Side Code

// Notice the option that I passed in as the second argument. This supposedly forces every 
// new client to create a new connection with the server but it either doesn't work or I'm 
// implementing it incorrectly. It is the very last configuration option listed in the 
// documentation linked to above.
var socket = io.connect('http://' + location.host, {'force new connection' : true });
socket.on('message', function (tweet) {
  var t = JSON.parse(tweet);
  if (t.image) {
    $('.hero-unit').prepend('<div class="media"><a class="pull-left" href="#"><img class="media-object" alt="64x64" style="width: 64px; height: 64px;" src="' + t.image + '"></a><div class="media-body"><h4 class="media-heading">' + t.user + '</h4>' + t.text + '</div></div>');
  } 
});

If I am thinking of this incorrectly or if there's something wrong with my code I am definitely open to any suggestions. I'd also be happy to reply with any additional details.

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
user1907342
  • 41
  • 1
  • 2
  • 2
    Multiplexing of socket.io can only apply to connections between the same client and server. It's technically impossible to use the same socket to communicate with different communication partners at the same time (unless you use multicasting, which doesn't work on TCP). – Philipp Dec 17 '12 at 00:24

1 Answers1

0

I would try something like this

Serverside:

io.sockets.on('connection', function (socket) {
    //Other Connectiony goodness here.
    });
});

tweet.stream('statuses/filter', { track : 'new orleans' }, function (stream) { 
    stream.on('data', function (data) {
      // The following lines simply pre-process data sent from Twitter so junk isn't
      // unnecessarily sent to the client.
      if (data.user) {
         tweets = {
         text  : data.text,
         image : data.user.profile_image_url,
         user  : data.user.name
         };
         var t = JSON.stringify(tweets);
         console.log(t);
         io.sockets.emit("tweet", t);
      }  
});

Client-side:

var socket = io.connect('http://' + location.host, {'force new connection' : true });
socket.on('tweet', function (tweet) {
  var t = JSON.parse(tweet);
  if (t.image) {
    $('.hero-unit').prepend('<div class="media"><a class="pull-left" href="#"><img class="media-object" alt="64x64" style="width: 64px; height: 64px;" src="' + t.image + '"></a><div class="media-body"><h4 class="media-heading">' + t.user + '</h4>' + t.text + '</div></div>');
  } 
});

Basically have the stream from twitter outside your socket, and then on a new tweet emit a message to all connected.

Jason Nichols
  • 3,739
  • 3
  • 29
  • 49