Encontros Comunitários GU
Mobile-RS Websockets e Android
Apoio:
jacksonfdam
http://about.me/jacksonfdamhttps://bitbucket.org/jacksonfdamhttps://github.com/jacksonfdamhttp://linkedin.com/in/jacksonfdam@jacksonfdam
GU Mobile RS
Somos um grupo destinado a compartilhar e promover encontros de desenvolvedores mobile no Rio Grande do Sul.
EventosColaboramos para eventos de desenvolvimento.
OficínasRealizamos encontros para por em prática o desenvolvimento de aplicativos móveis em diversas plataformas.
Aplicações real-time
Quando se fala de aplicações real-time, estamos técnicamente falando de conexões bi-direcionais, que na prática, é uma conexão que se mantem aberta (keep-alive) para que os clientes interajam com o servidor em uma única conexão aberta. A grande vantagem disso é de não precisar mais das requisições assíncronas (AJAX) para simular uma “ação quase real-time”, digo quase pois AJAX não é uma conexão bi-direcional capaz de se manter aberta até o término de seu processamento.
Realtime App
• Chat• Stream de atividades• Notificações• Colaboração• Jogos multiplayer• Dados em tempo real• Dashboards• Experiências 2 telas
CometComet é um modelo de aplicação web que tem como principal característica a utilização de uma ligação persistente HTTP que permite ao servidor transmitir dados para o cliente sem que exista um pedido explícito.
Esta técnica é chamada de Tecnologia Push.
O termo Comet representa um grupo de recursos e técnicas utilizados para a interação bilateral.
Fonte:http://en.wikipedia.org/wiki/Comet_%28programming%29
Websockets
É uma tecnologia que permite a comunicação bidirecional por canais full-duplex sobre um único soquete (TCP).
SuporteTodos os browsers mais atuais com exceção do browser Android suportam a ultima especificação do protocolo.• Internet Explorer
10+• Mozilla Firefox 4+• Safari 5+• Google Chrome 4+• Opera 11+
WebSocket Protocol Handshake
Enquanto o protocolo WebSocket em si é desconhecido dos servidores proxy e firewalls, ele possui um handshake HTTP compatível para que os servidores HTTP possam compartilhar seu padrão HTTP e HTTPS portas (80 e 443) com um gateway ou servidor WebSocket.
O protocolo WebSocket define um ws:// e wss:// prefixo para indicar um WebSocket e uma conexão segura WebSocket, respectivamente.
WebSocket Protocol Handshake
Client request
GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com
Server response
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat
WebSocket Protocol Handshake
Uma vez que a conexão é estabelecida entre o cliente e o servidor, podemos enviar dados ou estruturas de texto em ambas as direções no modo full-duplex.
WebSocket Example
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");
Sintaxe Javascript
WebSocket Example
exampleSocket.onopen = function (event) { exampleSocket.send("Here's some text that the server is urgently awaiting!"); };
Sintaxe Javascript
WebSocket Example
exampleSocket.onmessage = function (event) { console.log(event.data);}
Sintaxe Javascript
E agora?
NODE.JSWTF? Conhecendo a tecnologia
Node.js
Node.js se tornou popular devido a sua facilidade em trabalhar com real-time, simplesmente por que o protocolo WebSockets (Protocolo do HTML5 para conexões bi-direcionais) utiliza-se Javascript também.
• Orientado a eventos• Lado do servidor • JS não bloqueante
Mais em: http://udgwebdev.com/nodejs-para-leigos-introducao/
Node.js
Google V8 Motor• Engine JS Open source do Google (usado no
Google Chrome)• Sem JIT (Just-In-Time), todos JS compilado para
assembler• Otimizações como inlining, elisão de propriedades
em tempo de execução ... • Garbage Collector implementado / melhorado
http://en.wikipedia.org/wiki/Inlininghttp://en.wikipedia.org/wiki/V8_(JavaScript_engine)http://en.wikipedia.org/wiki/Copy_elision
Node.js
CommonJS • Conjunto de especificações para JS fora do
navegador • Node.js implementa algumas especificações
– ex. módulos • Deve haver uma função chamada require• Deve haver uma var chamada exports
Node.js
Módulos • O Node.js fornece alguns módulos principais como
o http, tcp, fs, sys... – procurará o módulo na pasta node_modules
hierarquicamente– se não for encontrado, vai olhar nos caminhos descritos
no NODE_PATH
var http = require ('http');
Node.js
Exemplo de Módulo
var PI = Math.PI; exports.area = function (r) {
return PI * r * r; }; exports.circumference = function (r) { return 2 * PI * r; };
Exemplo de definição em meuModulo.js
var meuModulo = require(‘./meuModulo .js’);
Include do meuModulo.js em outro arquivo
Node.js
Gerenciamento de Dependências
• Node packet manager (npm) • express (rotas)• socket.io (websockets)• ..
Node.js
Package.json
{ "name": ”Fisl 15 Chat", "version": "1.0.0", "description": "Real time chat com Android", "author": ”Jackson F. de A. Mafra", "scripts": { "start": "node app.js" }, "dependencies": { "socket.io": "latest", "express": "latest", "jade": "latest" } }
npm install
Node.js
Webserver em Node.JS
var http = require('http'); http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World, Wellcome to FISL15\n'); }).listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/');
node app.js Server running at http://127.0.0.1:1337/
Node.js
Express.js
Uma web framework para node.js inspirada em sinatra
var express = require('express'); var app = express(); app.get('/', function(req, res){
res.send('Hello World'); }); app.listen(3000);
Node.js
Socket.io
É uma camada de abstração para WebSockets com fallback para : • Flash socket• AJAX Long-polling• AJAX multi-part streaming• JSONP polling• iFrame
Node.js
Manipulação Eventos
io.sockets.on('connection', function(socket) {}); //initial connection from client
socket.on('message', function(message) {}) //message handler triggered when message is received
socket.on('disconnect', function() {}) //triggered when socket disconnects
socket.on('custom_event', function(data) {}) //event handler for custom event
Node.js
Enviando Mensagens
messages socket.send(JSON.stringify({user:’jackson', message: 'Welcome to Fisl15'}) ); //sends a message to the connected client
socket.broadcast.send(JSON.stringify({user:’jackson', message: 'Welcome to Fisl15'}) ); //sends a message to all clients except the owner of the socket
Node.js
Emitindo Eventos
socket.emit('user:join', {name: ’jackson'}); //triggers a custom event
socket.broadcast.emit('user:joined', data); //sends a message to all clients except the owner of the socket
Node.js
Anexar informações ao socket
socket.set('nickname', data.name, <optional_callback>);
ANDROIDPreparando o aplicativo cliente
Injeção de Dependência
Injeção de dependência é um padrão de projeto de software que permite a remoção de dependências hard-coded e torna possível para mudá-los, seja em tempo de execução ou em tempo de compilação. [Fonte: Wikipedia]
http://en.wikipedia.org/wiki/Dependency_injection
Injeção de Dependência
A Injeção de Dependências (também conhecida como Inversão de Controle) está presente em diversos frameworks populares como Spring ou Google Guice. Porém, estes últimos foram desenvolvidos pensando na JVM e não em ambientes móveis como o Android. Enquanto o RoboGuice procura melhorar a usabilidade do Guice no Android, o Dagger segue uma abordagem diferente, concentrando-se em funcionalidades simplificadas e melhor desempenho.
http://www.infoq.com/br/news/2012/10/dagger-injecao-android
Injeção de dependência
Injeção de Classes
Dagger
Injeção de views
Butter Knife
Universal
RoboGuiceAndroid Annotations (AA)
Mais em: http://java.dzone.com/articles/how-become-lazy-productive
Criando o projeto
O cliente de chat Android deve ser capaz de enviar e receber mensagens a partir de uma sala de bate-papo.
Inicie o Android Studio e crie um novo projeto chamado FislChat com o package io.github.gumobilers.fislchatCriar uma atividade em branco chamado ChatActivity
Definindo o layout
O fragmento irá conter o layout da nossa aplicação de chat. Abra o fragment_chat.xml (ou o nome que você deu para o layout) e defina:
• Uma ListView que conterá as mensagens de bate-papo (dica: android: stackFromBottom = "true" android: transcriptMode = "alwaysScroll" pode ajudá-lo)
• Um EditText para escrever a mensagem que deseja enviar para a sala de bate-papo
• Um botão para enviar a mensagem• Execute o aplicativo e ver que você começa o layout
desejado
Adicionando o RoboGuice
A instalação do RoboGuice requer que você baixe os seguintes arquivos JAR e adicioná-los ao seu classpath.
http://repo1.maven.org/maven2/org/roboguice/roboguice/2.0/roboguice-2.0.jarhttp://repo1.maven.org/maven2/com/google/inject/guice/3.0/guice-3.0-no_aop.jarhttp://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar
RoboGuice: Dependency Injection for Android - Michael Burtonhttps://www.youtube.com/watch?v=6wU2vwwiwPE
Adicionando o RoboGuice
Para utilizar RoboGuice para a injeção de dependência, é preciso adicioná-lo como uma dependência do projeto. • Abra o arquivo gradle.build e adicionar a dependência RoboGuice
sob o elemento dependências .• compile 'org.roboguice: roboguice: 3.0b-experimental’ • Certifique-se de que RoboGuice aparece em suas bibliotecas
externas • Nossos componentes Android precisará estender classes específicas
RoboGuice ter DI no lugar. • Edite seu fragmento e estendem-se desde RoboFragment • Edite você Atividade e estendem-se desde RoboFragmentActivity
Huston we have a problem!
Em caso de problemas:No Android Studio clique no botão Sync Project with Gradle File, deixe o AVD Manager fazer o trabalho. Sem restart, sem ./gradlew clean ou ./gradlew build.
Tambem pode ir em Tools-->Android-->Sync Project with Gradle File.
Injetando dependências
Para interagir com os componentes de layout, vamos usar a injeção dependência RoboGuice
• Adicionar um campo privado do tipo ListView e anotá-lo com @InjectView para obter uma referência da lista declarados (ex: @InjectView (R.id.messageList) private mMessageList ListView;)
• Adicionar um campo privado do tipo EditText e anotá-lo com @InjectView para obter a referência da entrada de texto declarado.
• Adicionar um campo privado do tipo Button e anotá-lo com @InjectView para obter a referência do botão declarado.
Adicionando a lógica
A injeção acontece durante o método onViewCreated em seu fragmento, de forma a garantir que as dependências já foram injetadas estaremos interagindo com eles no mesmo ponto.
1. Sobrescrever o método onViewCreated:
@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); }
1. De forma a interagir com o elemento da lista, é preciso fornecer um adaptador. 2. Vamos adicionar um simples ArrayAdapter de String para agora:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1);mMessageList.setAdapter(adapter);
Injetando um serviço de sistema
Vamos agora fazer o nosso telefone vibrar quando enviar uma mensagem.
Adicionar a permissão Vibrar em seu AndroidManifest.xml
<uses-permission android:name="android.permission.VIBRATE" />
Adicionar um campo particular do tipo Vibrator em seu fragmento e anotá-lo com a JSR-330 anotação @Inject.
Adicionar a lógica para vibrar 1000 milissegundos quando o envio da mensagem
NODE.JSConstruindo o servidor com Node.js e Socket.io
Criando o projeto Node.js
Para ter a estrutura do projeto, vamos contar com o express.js (semelhante ao sinatra). Instale expressar globalmente com o seguinte comando:
npm install –g express
Agora vamos criar um aplicativo baseado expressa chamado fislchat
express fislchat
Criando o projeto Node.js
A seguinte estrutura será criada
create : fislchat create : fislchat/package.json create : fislchat/app.js create : fislchat/public create : fislchat/views create : fislchat/views/layout.jade create : fislchat/views/index.jade create : fislchat/public/images create : fislchat/routes create : fislchat/routes/index.js create : fislchat/routes/user.js create : fislchat/public/stylesheets create : fislchat/public/stylesheets/style.css create : fislchat/public/javascripts
Criando o projeto Node.js
Observe que um arquivo chamado package.json contendo as dependências foi criado. Execute npm install para adicioná-las ao projeto (verifique que a pasta node_modules é criada e contém as dependências).
O app.js é o ponto de entrada para o nosso aplicativo, ele importa os módulos necessários, define algumas rotas e cria o servidor http. Abra e dê uma olhada nisso. Isso deve ser o suficiente para começar a nossa aplicação.
Executar node app ou npm start para iniciar o aplicativo. Verifique se digitando 'http://localhost:3000/' no seu navegador lhe dá a página de boas-vindas.
Adicionando o Socket.io
Até agora, você deve estar familiarizado com packages.json. De forma que para adicionar o suporte ao Socket.io precisamos defini-lo como uma dependência de tal arquivo, abra-o e adicione: "socket.io": "~ 0.9.16".
Execute npm install novamente para buscar a dependência.
Vamos agora criar um módulo que irá encapsular a lógica do socket.io. Crie um arquivo chamado socket.js dentro da pasta rotas.
Este módulo irá usar a dependência socket.io já definida. Importe no módulo :
var socketio = require ('socket.io');
Adicionando o Socket.io
Os módulos contêm lógica privada para a próprio módulo, que encapsulam a lógica, mas lembre-se que eles também podem expô-la usando a convenção CommonJS (com exportações das variáveis). Vamos expor uma função chamada initialize então podemos inicializá-la a partir de outro módulo:
exports.initialize = function(server) { io = socketio.listen(server);}
Nós adicionamos um parâmetro de servidor (este será o servidor http já criado no arquivo app.js) e nós inicializamos socketio, a fim de começar a aceitar conexões. Agora é hora de usar o nosso módulo.
Usando nosso módulo Socket.io
var server = http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port'));});
Abra a app.js e adicione o módulo que acabamos de criar
var io = require (’./routes /socket.js.').
Lembre-se que nós expomos a função initialize esperando um servidor http como parâmetro. Se você rolar no final do arquivo, você vai ver como o servidor http é criado (por padrão escutar no porto 3000).
Permite obter uma referência nesse servidor para que possamos passá-lo para o módulo
Usando nosso módulo Socket.io Agora você pode chamar a função initialize, passando o parâmetro do servidor:
io.initialize (server);
Inicie o aplicativo novamente (app nó) e verificar se você ver algo como
info - socket.io
iniciada no console.
Manipulação de eventos
Agora temos o app já ouvindo as conexões WebSocket , mas precisamos lidar com os eventos ( nova conexão, desconexão , mensagens ...) . Vamos adicionar um listener de conexão dentro do método initialize :io.sockets.on('connection', function(socket) { // All your handlers here, socket will be the connected client});
Manipulação de eventos
Fornecer um handler para o evento 'user : setname ‘.
Este será acionado pelo cliente logo após a conectar. ( Dica : . Lembre socket.on ( 'event' , function ( data) { })
A mensagem recebida será algo semelhante a { ' nickname': ' jackson'} .
Defina o valor para a sessão de socket para que possamos lembrar o nome do usuário e não forçá-lo a ser enviar toda vez ( dica: use socket.set ) .
Transmita uma mensagem como { ‘mensagem: ' jackson entrou !’ } para todos os usuários conectados .
Manipulação de eventos
Forneça um handler para o evento 'user : mensagem’.
Este evento será acionado quando um usuário envia uma mensagem para o chat.
Os dados será um JSON semelhante a este: {' mensagem ': ' Olá '} .
Transmita a mensagem para todos os outros clientes que adicionaram o apelido para ele ( dica: use socket.get(var, function (err, nickname) {}) )
para obter o apelido previamente armazenado ) .
A mensagem resultante deve ser como :{' mensagem ': ' Olá ', ' apelido ': ' jackson'}
Manipulação de eventos
BÔNUS:
Guarde os nomes de usuário em um array var users = []; , armazenar o nome quando se conectar e remova-o quando ele se desconectar.
ANDROIDComunicando o cliente com o socket.io
Incluindo Dependências
Não há nenhum suporte para Socket.io no Android , mas vamos adicionar uma biblioteca a partir de um repositório Maven. Abra o arquivo build.gradle e adicione o seguinte repositório sob o elemento repositórios:
repositories { mavenCentral() maven { url "http://audiobox.keytwo.net" }}
Vamos adicionar agora as duas dependências que requerem
compile 'io.socket:socket.io-client:0.2.1'compile 'com.squareup:otto:1.3.4'
Socket-io: https://github.com/fatshotty/socket.io-java-clientOtto: https://github.com/square/otto
Criando o serviço
De forma a manter a conexão em segundo plano, vamos criar um serviço que irá gerenciar nossos WebSockets. Crie uma classe chamada ChatService que estenda RoboService.
Adicione a definição de serviço no arquivo AndroidManifest.xml, para conhecimento da aplicação: <service android:name=".ChatService" />
Agora que temos o serviço, nós vamos ter que iniciá-lo. Um bom lugar para iniciá-lo, seria de uma classe de aplicação(Application).
Criar e uma classe chamada ChatApplication e inicie o serviço no método onCreate. Você deve ter algo semelhante a isto:
Criando o serviço
public class ChatApplication extends Application {
@Override public void onCreate() { super.onCreate();
// Start the service here } }
Volte para o arquivo AndroidManifest.xml e adicione o nome do aplicativo que você acabou de criar:
<application android:name=".ChatApplication"
Adicionando o evento de
barramentoOtto é um barramento de evento destinado a separar diferentes partes do seu aplicativo enquanto ainda permite que elas se comuniquem de forma eficiente.
http://square.github.io/otto/
Bus bus = new Bus(); //creates the bus (better use dependency injection)
bus.post(new ServerMessage("This is awesome")); //publish the message //synchronous delivery
Publicando
Adicionando o evento de
barramento
@Subscribe public void receiveMessage(ServerMessage serverMessage) {
// TODO: React to the event somehow!
}
Assinando
Adicionando o evento de
barramento
• register(), unregister(), post() • @Subscribe, @Produce• Thread confinement • Testes simples
Otto API
Adicionando o evento de
barramento
Vamos criar um módulo RoboGuice para tornar o singleton Bus e reutilizá-lo em todo o aplicativo. Criar uma classe interna no ChatApplication:
Otto API
Adicionando o evento de
barramento
class ChatModule implements Module { @Override public void configure(Binder binder) { // Figure out how to declare a singleton Bus } }
Agora adicione essa linha logo antes de iniciar o serviço, para que o RoboGuice saiba sobre o nosso módulo:
Otto API
Adicionando o evento de
barramento
RoboGuice.setBaseApplicationInjector(this, RoboGuice.DEFAULT_STAGE, RoboGuice.newDefaultRoboModule(this), new ChatModule());
Agora você está pronto para injetar o Bus tanto no ChatService e ao ChatFragment. Crie um campo privado do tipo Bus e usar a anotação @Inject.
Otto API
Adicionando o evento de
barramento
Uma última coisa, a fim de receber eventos (também se aplica aos produtores), uma instância de classe precisa se registrar com o barramento. Adicione o seguinte código para o ChatFragment
Otto API
Adicionando o evento de
barramento
@Override public void onResume() { super.onResume(); mBus.register(this); }
@Override public void onPause() { super.onPause();
// Always unregister when an object no longer should be on the bus. mBus.unregister(this); }
Adicione o seguinte código para o ChatService
Otto API
Adicionando o evento de
barramento
@Override public void onCreate() { super.onCreate(); mBus.register(this); }
@Override public void onDestroy() { super.onDestroy(); mBus.unregister(this); }
Adicione a permissão INTERNET para o seu AndroidManifest.xml para que possa se conectar ao servidor.
Interagindo com o Servidor com o
Socket.io
<uses-permission android:name="android.permission.INTERNET"/>
Vamos agora abrir um WebSocket com o servidor no ChatService. Crie um campo privado do tipo SocketIO e um método de inicialização (initialize) para inicializar Socket.io:
socket = new SocketIO("http://127.0.0.1:3000/");
socket.connect(new IOCallback() { @Override public void onMessage(JsonElement json, IOAcknowledge ack) { System.out.println("Server said:" + json.toString()); }
@Override public void onMessage(String data, IOAcknowledge ack) { System.out.println("Server said string: " + data); }
@Override public void onError(SocketIOException socketIOException) { System.out.println("an Error occured"); socketIOException.printStackTrace(); }...
Interagindo com o Servidor com o
Socket.io
@Override public void onDisconnect() { System.out.println("Connection terminated."); }
@Override public void onConnect() { System.out.println("Connection established"); }
@Override public void on(String event, IOAcknowledge ack, JsonElement... args) { System.out.println("Server triggered event '" + event + "'"); } });
Interagindo com o Servidor com o
Socket.io
Logo após ter uma conexão bem-sucedida, emite evento de user: setname e enviar uma mensagem como {'apelido': ’jackson'} (você pode codificar o nome de usuário até agora)
Definindo o apelido
• servidor irá enviar mensagens JSON no seguinte formato {’message': ’Ola', 'Apelido': ’jackson'}.
Crie uma classe chamada ServerMessage que representa esse esquema e sobreescreve o método toString (vamos usá-lo para exibir as mensagens na interface do usuário).
Vamos interpretar mensagens sem apelido para ser mensagens do sistema, então isso vai como vamos mostrar mensagens:
As mensagens do sistema -> / / mensagem (ex:, / / jackson entrou na sala) Mensagens do usuário -> apelido: mensagem (ex:, jackson: Chatiado!)
Recebendo mensagens
public String toString() { return nickname != null ? nickname + ": " + message : "//" + message; }
Agora você pode implementar o método onMessage (a versão String), convertendo a mensagem recebida para um ServerMessage com Gson (você tem já como uma dependência, dica: use o método fromJson).
Esta mensagem precisa ser exibida na interface do usuário, mas como queremos ter tudo dissociado, vamos enviá-la para o barramento de evento, para um assinante pode processá-lo. AVISO: Por padrão, toda a interação com uma instância Bus é confinada na Main Thread, mas o serviço está sendo executado em uma Thread diferente. A fim de ser capaz de postar o evento para a Main Thread apartir do ChatService, estaremos usando uma solução de meio hacky.
Recebendo mensagens
private final Handler mHandler = new Handler(Looper.getMainLooper());
public void post(final Object event) { if (Looper.myLooper() == Looper.getMainLooper()) { mBus.post(event); } else { mHandler.post(new Runnable() { @Override public void run() { mBus.post(event); } }); } }
Copie e cole o seguinte método no ChatService e postar a mensagem de usá-lo:
Recebendo mensagens
Temos agora a mensagem publicada para a o barramento, vamos adicionar um assinante para o evento.
O assinante deve ser definido no ChatFragment para que possamos atualizar o adaptador base no evento.
Altere a definição do adaptador de ArrayAdapter <String> para ArrayAdapter <ServerMessage> e atualizá-lo a partir do método de assinantes.
Execute o aplicativo e verificar que as mensagens são recebidas e adicionado à lista.
Recebendo mensagens
Quando pressionar o botão Enviar queremos que as mensagens sejam enviadas para o WebSocket.
Para isso, vamos criar uma classe chamada ClientMessage que representa o esquema a ser enviado ({'mensagem': 'Olá'}).
Usando a instancia de barramento que injetamos, postamos a mensagem e definimos um assinante no ChatService , responsável por enviá-lo para a WS (dica: use Gson novamente para converter de Object para String, toJson)
Enviando mensagens
BROWSERCriando um cliente HTML
Crie um arquivo em seu diretório público chamado chat.html (O Node.js irá servi-la como um recurso estático) e adicione o seguinte esqueleto HTML5:
Construindo o cliente do navegador
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>Mobos Chat</title> <!--[if lt IE 9]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--></head><body></body><script src="/socket.io/socket.io.js" ></script><script src="http://code.jquery.com/jquery-1.10.1.min.js"></script></html>
Adicione um input para escrever a mensagem, um botão e um div para exibir as mensagens de bate-papo.Crie um arquivo chamado chat.js dentro da pasta javascript para encapsular a lógica do socket.io
Construindo o cliente do navegador
var socket = io.connect('http://localhost'); socket.on('yourevent', function (data) { console.log(data); socket.emit('my other event', { my: 'data' }); });
var socket = io.connect('http://localhost'); socket.on('yourevent', function (data) { console.log(data); socket.emit('my other event', { my: 'data' }); });
Obrigado!@jacksonfdam