I have a problem w my Node Server + Socket Client.
Well, my localhost server works perfect.
But... when i connect my socket.io client (node) w my external server (ex: www.myserver.com:3000) doesnt works.
I dont recieve any data. (message var)
This is my sample code:
var io = require("socket.io-client");
var requestHTTP = require("request");
var socket = io('http://myserver.com:3000');
var room = "game881";
console.log('test simple socket '+room+'');
socket.on('news', function (data) {
console.log(data);
socket.emit('conectado', { my: 'Conectado!' });
});
socket.on('connect', function () {
socket.emit('room', room);
console.log('Conectando a ' + room);
});
socket.on('message', function (data) {
var json = data.message;
json = JSON.parse(json);
console.log(json);
});+
Why dont recieve any data?
CORS? I've already tried.
Port used?
:) thanks!
Well... i solved my problem.
I use this.
Setup Server-Server SSL communication using socket.io in node.js
The previous answers didn't do it for me. require('https').globalAgent is always >undefined.
Did some seaching and found the rejectUnauthorized parameter in the docs (https://nodejs.org/api/tls.html). Not sure if it's related to SocketIO, but it somehow seems to work with self-signed certificates:
var socket = io.connect('//yourhost:8000', {secure: true, rejectUnauthorized: false})
secure: true might be optional, but I like to enforce it anyhow.
Related
I'm trying to build a chat application using Laravel, with node js server, socketio and redis. What I have is this:
Client JS:
var socket = io('http://localhost:3005');
var room = '17';
$("#send").click(function(){
content = $("textarea").val();
id =$("#id").val();
$.ajax({
url: "{{route('send.message')}}",
method: "POST",
data: {content, id, room},
success: function(){
}
});
});
socket.on('cacad', function(message){
console.log(message); //multiple copies here
});
socket.on('connect', function(){
console.log("Connected!");
socket.emit('room', room);
});
Laravel Controller:
public function sendMessage(Request $request){
event(new EventName($request->all()));
$message = new Message;
$message->message = $request->content;
$redis = LRedis::connection();
$redis->publish('chat-channel', json_encode($request->all()));
$message->save();
}
Node Server:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var redis = require('ioredis');
var myMessage;
var redis_client = redis.createClient();
redis_client.subscribe('chat-channel');
io.on('connection', function(socket) {
redis_client.on('message', function(channel, message) {
var myData = JSON.parse(message);
socket.broadcast.to('17').emit('cacad', 'u i u a a');
});
socket.on('room', function(room){
socket.join(room);
});
socket.on('disconnect', function(){
console.log("disconnected!");
});
});
http.listen(3005, function() {
console.log('Listening on Port 3005');
});
I am trying to broadcast a message u i u a a in room 17. But when I receive it in the console, it shows multiple copies of it, 2x-4x. In the Laravel controller I publish a message using redis and I subscribe to it in node server. It is received successfully, but the problem lies with the multiple copies of the message (client side).
Please where is it wrong? Thank you :)
I'm pretty convinced I found the issue although I had to search a bit about those simple API usage because I'm not using the library lately.
Looking at the docs it's explain your issue pretty clearly.
Here you are listening to a new connection,
io.on('connection', function(socket) {
If the client asked to join to a specific room, you join him:
socket.on('room', function(room){
socket.join(room);
So far it's like the docs:
io.on('connection', function(socket){
socket.join('some room');
});
But your issue is with your emit, on each client connection, you listen to a message from your redis. Then you broadcast it to the room with an emit of the connected client.
Instead of that, you can do this:
io.on('connection', function(socket) {
socket.on('room', function(room){
socket.join(room);
});
socket.on('disconnect', function(){
console.log("disconnected!");
});
});
redis_client.on('message', function(channel, message) {
var myData = JSON.parse(message);
io.to('17').emit('cacad', 'u i u a a');
});
I think this happens on the socket-io-client side. not on the server-side. when I was using react-js for the client-side. I received the same message multiple times.
with the same server, I imported socket-io-client 4.4.1 in the vanilla js front-end project. then I didn't get multiple messages... :)
try use latest socket io client versions. i think they have fixed the issue in the latest versions..
I wish to securely send messages back and forth between a client and a remote server (just an IP address and a port) using nodejs. The client runs a local .js file and does not use a browser. I have tried to do so using the node TLS module (https://nodejs.org/api/tls.html).
The handshake works perfectly fine, but I can not manage to send a message from the server to the client. My current code is:
client.js
const tls = require('tls');
const fs = require('fs');
const options = {
host: <server IP address>,
port: <port number>,
key: fs.readFileSync('client.key'),
cert: fs.readFileSync('client.crt'),
ca: fs.readFileSync('ca.crt'),
checkServerIdentity: function (host, cert) {
return undefined;
}
};
const client = tls.connect(options, function(){
if (client.authorized) {
console.log("Connection authorized");
} else {
console.log("Connection not authorized: " + conn.authorizationError)
}
process.stdin.pipe(client);
process.stdin.resume();
client.emit('data','message')
});
client.setEncoding('utf8');
client.addListener('data', function(data) {
console.log(data);
});
client.on('end', () => {
server.close();
});
server.js
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt'),
ca: fs.readFileSync('ca.crt'),
requestCert: true,
rejectUnauthorized: true
};
const server = tls.createServer(options, function(socket){
console.log('server connected',
socket.authorized ? 'authorized' : 'unauthorized');
socket.setEncoding('utf8');
socket.pipe(socket);
socket.emit('data','I am the server')
});
server.listen(<port number>,function(){
console.log('listening')
})
server.on('connection',function(client){
console.log('client connected')
client.on('data',function(data){
console.log(data)
})
})
The server does output 'client connected' but does not do anything with the client.on() part, and I can not find another way to make the server listen for messages from the client. Is there a way to use the tls module so that I can make the client and server interact based on the messages they send and receive? Again, I do not want to use a browser.
The comments by #robertklep helped me solve my issue. Delete the socket.pipe(socket) line on the server side, and on the client side just use socket.write() to send a message to the server. This can be received by a socket.on('data') instance on the server side. Also, to interact with multiple clients, you can write something like:
var socket = {};
const server = tls.createServer(options, function(s){
client=s.getPeerCertificate().subject.CN
socket[client] = s;
socket[client].setEncoding('utf8');
socket[client].write('welcome')
for (key in socket){
socket[key].write('new client connected')
}
socket[client].on('data',function(data){
socket[client].write('data received')
})
I think using a Set for notifying new connections of being connected makes more sense. An object being added to a set must be unique to the set if it is to be added. You can also just use socket.server._connectionKey to determine what client it is, don't have to mess around with getting the peer certificate.
var sockets = new Set();
const server = tls.createServer(options, (socket) => {
console.log('server connected',
socket.authorized ? 'authorized' : 'unauthorized');
var sock_set_len = sockets.size; //get size of sockets set
var key = socket.server._connectionKey;
sockets.add(key); //attempt to add socket to connection list
if(sock_set_len < sockets.size) { //if the socket _connectionKey is unique, it will be added, and will be treated as a new connection here.
socket.write("you are connected...");
}
socket.on('data',function(data){
socket.write(data);
})
socket.on('end', socket.end);
});
On a side note, I created a package to handle sockets with Obj-C iOS, taking into account the latest (iOS 13) TLS restrictions imposed by Apple:
https://github.com/eamonwhiter73/IOSObjCWebSockets
I used a Node JS TLS server to receive connections, a variation of the echo server example in the Node JS docs
It is simple chat app using node.js and socket.io. This app work fine in my local computer but do not work when I upload it to the server: Please look at my code on remote server and the problem.
Here is the code snippet of client:
<script type="application/javascript">
var socket = io.connect();
eventHandler(socket);
function eventHandler(socket) {
socket.on('connect', function(){
socket.emit('adduser', prompt("What's your name?"));
});
socket.on('error', function () {
console.log("Connection error"); //It works after a few second with error
});
}
$(document).ready(function(){
.....
});
</script>
It looks like on the remote server Socket.IO 0.9.16 is installed (which is not up-to-date). If you're writing code according to new documentation this might be a reason why it doesn't work as you expected.
Try to upgrade Socket.IO to 1.0
This change worked for me:
you wrote this method:
var socket = io.connect();
Thanks to another help page, I switched this method to this:
var socket = io.connect('http://localhost:8080');
You can replace "localhost" with whatever ip address you use to access your server.
Also, just in case - if you haven't, it would be useful to include a connection notification on your server in the app.js file. mine looks like the following:
var fs = require("fs")
, http = require("http")
, socketio = require("socket.io");
var server = http.createServer(function(req, res) {
res.writeHead(200, { "Content-type": "text/html"});
res.end(fs.readFileSync(__dirname + "/index.php"));
}).listen(8080, function() {
console.log("Listening at http://localhost:8080");
});
socketio.listen(server).on("connection", function(socket) {
console.log("CONNECTED");
socket.on("message", function(msg) {
console.log("Message received: ", msg);
socket.broadcast.emit("message", msg);
});
});
You can also see the help page I linked to in case they have something that more closely relates to your issue.
Your page seems to be working for me. Make sure your page is fully loaded before executing your script. This is done by using window.onload like this:
<script>
window.onload = function() {
//Your code here
}
</script>
I try socket.io again since v.1.0 released.
As the doc,
https://github.com/Automattic/socket.io
Server side:
var server = require('http').Server();
var io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('event', function(data){});
socket.on('disconnect', function(){});
});
server.listen(5000);
Client side
var socket = io.connect('http://yourhostname.com/');
In development, surely
var socket = io.connect('http://localhost:5000/');
It works, but I'm very uncomfortable with hardcoding the hostname(subdomain.domain) in the client code(/index.js).
The index.js is hosted by the http-sever and the socket.io is bundled to the http-server in this configuration.
Is there any smart way not to hardcode the hostname but to code in some relative path?
Thanks.
EDIT:
When I try:
var socket = io.connect('./');
The connection error:
GET http://.:5000/socket.io/?EIO=2&transport=polling&t=1401659441615-0 net::ERR_NAME_NOT_RESOLVED
is like this, so at least the port number (5000) is obtained properly without hardcoding in the client side.
Final answer.
I have totally forgotton that we can obtain the current url/domain in browser.
window.location.hostname
So, simply goes:
'use strict';
/*global window, require, console, __dirname, $,alert*/
var log = function(msg)
{
console.log(msg);
};
log('init');
$('document').ready(function()
{
var io = require('socket.io-client');
var socket = io.connect(window.location.hostname);
socket.on('connect', function()
{
log('socket connected');
});
});
You have to remember that Node.js is not a web server. It's a platform. When you specify a relative path, it doesn't know that you mean "relative to the current domain."
What you need to do is send the domain to the client when you send them the webpage (I don't know the specifics of your setup, but perhaps using a template variable?), and send them the localhost:5000 domain if you're in development, or your real domain if you're in production (alternatively, you can use a library like nconf, but you get the idea).
dunno, so far I did as follows:
'use strict';
/*global window, require, console, __dirname, $,alert*/
var log = function(msg)
{
console.log(msg);
};
log('init');
$.getJSON("../config.json", function(data)
{
var host = data.url;
var port = data.port;
$('document').ready(function()
{
alert(host + ':' + port);
var io = require('socket.io-client');
var socket = io.connect(host);
socket.on('connect', function()
{
log('socket connected');
});
});
});
It's browserified with socket.io-client.
I'm trying to create a test using LearnBoost's socket.io and the node-websocket-client. Communication between the client and server work great. After all communication is done, I close both the client and the server. Yet the program hangs, waiting on some unknown callback. Two questions:
What is the following program waiting for?
Is there a tool for diagnosing outstanding callbacks in node programs?
var connect = require('connect'),
io = require('socket.io'),
WebSocket = require('websocket-client').WebSocket;
var port = 7111;
var server = connect.createServer();
var socket = io.listen(server);
socket.on('connection', function(client) {
client.send('Welcome!');
client.on('message', function(message) {
console.log(message);
});
client.on('disconnect', function() {
console.log('closing');
server.close();
});
});
server.listen(port, function() {
var ws = new WebSocket('ws://localhost:' + port + '/socket.io/websocket');
ws.onmessage = function(message) {
console.log(message.data);
};
setTimeout(function() {
ws.send('~m~3~m~Yo!');
ws.close();
}, 10);
});
EDIT: changed the variable name of the WebSocket to ws to avoid confusion
var socket = io.listen(server);
You've created a socket on a port. You've never closed it.
socket.server.close() closes your (socket.io) socket.
When in doubt read the socket.io github examples
socket.server === server It's the server you pass in, in the liste statement so it's closed. I'm not sure what it's waiting for.
Below a way to shutdown all the connections and be able to run multiple expresso tests (using socket.io and socket.io-client).
The solution is tricky and buggy but works on 0.8.5. The main problem is regarding the library to use websockets (node-websocket-client).
Currently, on socket.io, the OS contributors have patched the websocket client. So, we must do the same on our socket.io-client npm package to be able to use finishClose method on the socket client side. Socket.io-client uses the websocket library as npm package, so you must find the file (websocket.js) and substitute it with the same on socket.io.
Afterwards, you could use finishClose method to ensure the connections are closed and with some custom server/client socket settings, the tests will run correctly.
var io = require("socket.io").listen(port);
io.set('close timeout', .2);
io.set('client store expiration', .2);
var client = require("socket.io-client").connect( "http://localhost", { port: port , 'reconnect': false, 'force new connection': true});
client.on('connect', function() {
client.disconnect();
});
client.on('disconnect', function() {
client.socket.transport.websocket.finishClose();
io.server.close();
});
io.server.on('close', function() {
setTimeout( function() {
done();
}, 500);
});
Hope, somebody can help.
The program is waiting because socket.io (server) is still listening for incoming connections. I don't know of any way to stop listening.