Como fazer um servidor Java para múltiplos clientes Flash
por nunof, 19:57 20-03-2008 (actualizado em 20:58 07-07-2010)
Neste tutorial vamos fazer um servidor em Java capaz de lidar com vários clientes. O propósito do tutorial será construir uma aplicação de chat e usando o Flash para os clientes.
Introdução - Cliente Flash e servidor Java
Temos visto um constante aumento de aplicações multimédia online e o Flash é um candidato ideal para este tipo de aplicações. Tem as funcionalidades necessárias para fornecer uma interface rica, capaz de correr num browser.
Desde as suas versões mais recentes que o Flash ganhou a possibilidade de trabalhar com sockets (e não apenas XMLSockets). Sockets são uma extremidade numa comunicação e são usados para estabelecer uma conversa entre diferentes entidades. Isto abriu muitas possibilidades para as aplicações Flash.
O Java constitui uma boa escolha para um servidor multi-cliente. Tanto o Flash como o Java são soluções multi-plataforma, fazendo com que possam ser facilmente distribuídas.
Fazer uma aplicação de chat com o Flash e o Java
Neste tutorial vamos explorar estes conceitos e vamos fazer uma aplicação usando Flash como cliente e Java como servidor multi-cliente. Um exemplo duma aplicação simples que se encaixa neste domínio é uma aplicação de chat e faremos isso mesmo.
A Adobe introduziu umas protecções de segurança e para uma aplicação Flash poder ligar-se a um servidor, primeiro precisa de saber a política desse servidor, para garantir que tem acesso a este. Para resolver isto, faremos um servidor de política em Java (policy server), que também pode ser usado separadamente por outros servidores que necessitem que clientes Flash se liguem a eles.
Basicamente, a nossa aplicação de chat precisa de 3 intervenientes: cliente de chat em Flash, servidor de chat em Java e servidor de política em Java. Esta sinergia é descrita na imagem seguinte:

Iremos usar ActionScript 3 neste tutorial. Vou usar o Adobe Flash CS3 Professional para desenvolver o cliente em Flash.
Fazer o cliente do chat em Flash
Vamos começar por fazer o cliente Flash. Este será composto por 2 ficheiros diferentes:
- ChatClient.as: A classe ChatClient é responsável por comunicar com o servidor
- Chat.fla: O ficheiro principal de Flash com uma interface para o chat e o código para usar o cliente
Fazer com que a classe ChatClient fale com o servidor
Vamos começar por criar a nossa classe ChatClient. Esta classe terá a capacidade de enviar e receber simples mensagens do servidor. Para tornar isto possível, precisará de um socket e de saber o IP do servidor e a sua porta. Também vamos ter de passar um TextField para a classe ChatClient para que esta possa escrever as mensagens que recebeu.
A definição da classe e o seu construtor deverão estar assim descritos:
package { import flash.display.*; import flash.events.*; import flash.net.*; import flash.text.*; public class ChatClient extends Sprite { private var host:String; private var port:int; private var socket:Socket; private var chatArea:TextField; public function ChatClient(h:String, p:int, ca:TextField) { this.host = h; this.port = p; this.chatArea = ca; } }
Agora precisamos de fazer um método para nos ligarmos ao servidor e também para tratar dos eventos gerados pelo socket. Para trabalhar com sockets em Flash precisamos de adicionar escutas aos eventos dos sockets, que são chamados quando algo de significativo acontece. Podemos fazer isto usando o seguinte código (coloque-o na classe ChatClient):
public function connect():Boolean {
this.socket = new Socket(this.host, this.port);
this.socket.addEventListener(Event.CONNECT, socketConnect);
this.socket.addEventListener(Event.CLOSE, socketClose);
this.socket.addEventListener(IOErrorEvent.IO_ERROR, socketError);
this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
this.socket.addEventListener(ProgressEvent.SOCKET_DATA, socketData);
try {
this.socket.connect(this.host, this.port);
}
catch (e:Error) {
trace("Error on connect: " + e);
return false;
}
return true;
}
private function socketConnect(event:Event):void {
trace("Connected: " + event);
}
private function socketData(event:ProgressEvent):void {
trace("Receiving data: " + event);
receiveData(this.socket.readUTFBytes(this.socket.bytesAvailable));
}
private function socketClose(event:Event):void {
trace("Connection closed: " + event);
this.chatArea.appendText("Connection lost." + "n");
}
private function socketError(event:IOErrorEvent):void {
trace("Socket error: " + event);
}
private function securityError(event:SecurityErrorEvent):void {
trace("Security error: " + event);
}
O método connect apenas cria um novo socket com o servidor e porta fornecidos no construtor. Adiciona escutas aos eventos mais significativos e tenta ligar-se ao servidor.
A maioria dos eventos são tratados apenas para fornecer informações de estado (críticas para depuração de uma aplicação cliente-servidor). As excepções são os métodos socketData e socketClose. No método socketClose simplesmente escrevemos informação de estado para o cliente. O método socketData lê todos os bytes disponíveis no buffer do socket e chama o método receiveData que se encontra descrito de seguida.
As únicas coisas que faltam são o método para tratar dos dados recebidos e o método para enviar mensagens para o servidor. Vamos criar o método sendMessage para escrever uma mensagem no socket e o método receiveData para tratar dos dados recebidos através do método socketData. O código para estes métodos pode ser encontrado de seguida (este código pertence à classe ChatClient):
public function sendMessage(msg:String):void {
msg += "n";
try {
this.socket.writeUTFBytes(msg);
this.socket.flush();
trace("Message sent: " + msg);
}
catch(e:Error) {
trace("Error sending data: " + e);
}
}
private function receiveData(msg:String):void {
trace("Message received: " + msg);
this.chatArea.appendText(msg + "n");
}
A mensagem recebida é simplesmente escrita para o chat do cliente. O método sendMessage adiciona uma quebra de linha à mensagem antes de a escrever no socket. Não vamos escrever directamente a nossa própria mensagem no lado do cliente - vamos esperar que o servidor envie a mensagem para todos os clientes para apenas escrevermos nessa altura.
A nossa classe ChatClient está assim terminada.
Fazer a interface para o chat e o cliente Flash
Agora precisamos de fazer o principal ficheiro Flash com a interface. Será composto por uma caixa de texto, um botão para enviar mensagens e uma área de texto para mostrar as mensagens de conversação.
Comecem por adicionar um novo campo de texto. Chamem-lhe inputLine_txt e mudem o seu tipo para Input Text. Façam-no comprido o suficiente para conseguir levar uma linha de conversação.
Agora construam um botão e chamem-lhe send_btn. Será usado para enviar mensagens (alternativamente também usaremos o Enter).
A única coisa que falta adicionar é a área de texto onde mostraremos a conversação. Adicionem um novo campo de texto, chamem-lhe chatArea_txt e mudem o seu tipo para Dynamic Text. Certifiquem-se que Multiline está seleccionado.
Vejam a seguinte imagem para perceber este processo.

Agora precisamos de adicionar as acções. Criem um novo layer, escolham o primeiro frame e abram o painel de ActionScript.
Precisamos de fazer 3 coisas:
- Fazer o requerimento da política ao servidor
- Criar um ChatClient e ligar ao servidor
- Tratar do processo de enviar mensagens
Lembrem-se, e isto é importante, se o Flash não receber a política do servidor a confirmar que lhe é dado o acesso ao servidor, então a ligação ao servidor não pode ser estabelecida. O cliente Flash envia implicitamente um requerimento de política ao servidor (<policy-file-request/>) e espera que a política seja enviada. Podemos também definir explicitamente o requerimento da política a um local específico (esta será a nossa abordagem).
Depois de carregarmos o ficheiro com a política vamos criar um objecto da classe ChatClient e estabelecer uma ligação com o servidor. Precisamos de definir o IP do servidor e a porta. Neste exemplo, usarei um endereço privado, porque tenho vários computadores em LAN e posso testar a aplicação desta forma. Devem mudar o endereço IP para o do vosso servidor e também mudar a porta. Vou usar o mesmo IP para o pedido da política, mas noutra porta.
Em seguida, vamos adicionar escutas aos eventos que fazem disparar o envio da mensagem. Vamos definir uma função para enviar mensagens que verifica se o campo inputLine_txt não está vazio, depois usa o objecto da classe ChatClient para enviar a mensagem para o servidor e no final também limpa o texto do campo inputLine_txt.
O código para conseguir isto é o seguinte:
import ChatClient; import flash.display.*; var host:String = "192.168.1.12"; var chatPort:int = 5555; var policyPort:int = chatPort + 1; Security.loadPolicyFile("xmlsocket://" + host + ":" + policyPort); var client:ChatClient = new ChatClient(host, chatPort, chatArea_txt); client.connect(); send_btn.addEventListener(MouseEvent.CLICK, onSendClick); inputLine_txt.addEventListener(KeyboardEvent.KEY_UP, onInputLineKey); function sendMessage():void { if (inputLine_txt.text != "") { client.sendMessage(inputLine_txt.text); inputLine_txt.text = ""; } } function onSendClick(e:MouseEvent):void { sendMessage(); } function onInputLineKey(e:KeyboardEvent):void { if (e.keyCode == 13) { // ENTER was pressed sendMessage(); } }
E acabamos o cliente. Agora precisamos de fazer a parte do servidor.
Como fazer um servidor de política com Java
Como foi dito anteriormente, o Flash espera que o servidor trate dos seus requerimentos de política. A política é um XML que contém os endereços dos domínios que têm acesso ao servidor e também a que portas têm acesso. É uma medida de segurança que a Adobe introduziu no Flash e todos os servidores a que um cliente Flash se queira ligar com sockets têm de estar preparados para isto.
Um servidor de política pode ser feito facilmente com Java e podem usar esta solução para outros servidores aos quais precisem que os clientes Flash se liguem.
O servidor de política irá consistir em 2 classes diferentes:
- PolicyServer: espera por ligações de clientes e cria PolicyServerConnections para tratar delas
- PolicyServerConnection: lê requerimentos de política dos clientes e escreve a política para estes
Apenas vou explicar e colocar aqui o código dos métodos mais importantes. Os ficheiros deste tutorial incluem o código todo, que se encontra bem documentado.
Vamos começar por definir o PolicyServer. Esta classe contém a política em XML. Neste caso vou definir o servidor como aceitando ligações de qualquer domínio e para qualquer porta. Nas vossas aplicações deverão ser mais restritivos e apenas dar acesso limitado.
public class PolicyServer extends Thread { public static final String POLICY_REQUEST = "<policy-file-request/>"; public static final String POLICY_XML = "<?xml version="1.0"?>" + "<cross-domain-policy>" + "<allow-access-from domain="*" to-ports="*" />" + "</cross-domain-policy>"; protected int port; protected ServerSocket serverSocket; protected boolean listening; /**
* Creates a new instance of PolicyServer.
*
* @param serverPort the port to be used by the server
*/ public PolicyServer(int serverPort) { this.port = serverPort; this.listening = false; } /**
* Waits for clients' connections and handles them to a new PolicyServerConnection.
*/ public void run() { try { this.serverSocket = new ServerSocket(this.port); this.listening = true; debug("listening"); while (this.listening) { Socket socket = this.serverSocket.accept(); debug("client connection from " + socket.getRemoteSocketAddress()); PolicyServerConnection socketConnection = new PolicyServerConnection(socket); socketConnection.start(); }; } catch (Exception e) { debug("Exception (run): " + e.getMessage()); } } }
Isto é bastante simples e não necessita de grandes explicações. Colocamos algumas mensagens de debug que dão bastante jeito para percebermos o que se está a passar. Devem ver o código fonte para o resto dos métodos, mas não há muito mais do que isto.
Tratar dos pedidos de política do Flash em Java
Agora vamos definir a classe PolicyServerConnection. Esta classe vai ler pedidos de política dos clientes, testar se são válidos e nesse caso enviar-lhes a política em XML. Irá receber um socket do servidor e vai abrir um leitor e um escritor para o poder usar para conversar com o cliente.
Vamos fazer o método readPolicyRequest que irá ler uma mensagem do socket, certificar-se que é um pedido de política e chamar o método writePolicy. Este método irá escrever o ficheiro XML da política do servidor e fechar o socket.
A nossa classe PolicyServerConnection deverá estar assim:
public class PolicyServerConnection extends Thread { protected Socket socket; protected BufferedReader socketIn; protected PrintWriter socketOut; /**
* Creates a new instance of PolicyServerConnection.
*
* @param socket client's socket connection
*/ public PolicyServerConnection(Socket socket) { this.socket = socket; } /**
* Create a reader and writer for the socket and call readPolicyRequest.
*/ public void run() { try { this.socketIn = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); this.socketOut = new PrintWriter(this.socket.getOutputStream(), true); readPolicyRequest(); } catch (Exception e) { debug("Exception (run): " + e.getMessage()); } } /**
* Reads a string from the client and if it is a policy request we write the policy, then we close the connection.
*/ protected void readPolicyRequest() { try { String request = read(); debug("client says '" + request + "'"); if (request.equals(PolicyServer.POLICY_REQUEST)) { writePolicy(); } } catch (Exception e) { debug("Exception (readPolicyRequest): " + e.getMessage()); } finalize(); } /**
* Writes the policy of the server.
*/ protected void writePolicy() { try { this.socketOut.write(PolicyServer.POLICY_XML + "u0000"); this.socketOut.close(); debug("policy sent to client"); } catch (Exception e) { debug("Exception (writePolicy): " + e.getMessage()); } } }
Não se esqueçam que isso não está completo. Vejam o código fonte para o resto.
O nosso servidor de política está feito. Simples, não foi?
Fazer o servidor de chat em Java
A estrutura do servidor principal é parecida com a do servidor de política. Também vamos usar 2 classes para isto:
- ChatServer: espera por ligações dos clientes e cria ChatServerConnection para tratar delas, adiciona e retira clientes e envia mensagens para todos eles
- ChatServerConnection: lê e escreve mensagens de chat para os clientes
Vamos começar pela classe ChatServer. Reparem que é muito parecida com a classe PolicyServer. Vamos adicionar o método remove para quando os clientes quiserem sair do servidor e o métodos writeToAll para difundir mensagens para todos.
Aqui está parte da definição desta classe:
public class ChatServer extends Thread { protected ServerSocket socketServer; protected int port; protected boolean listening; protected Vector<ChatServerConnection> clientConnections; /**
* Creates a new instance of ChatServer.
*
* @param serverPort the port to be used by the server
*/ public ChatServer(int serverPort) { this.port = serverPort; this.clientConnections = new Vector<ChatServerConnection>(); this.listening = false; } /**
* Listens for client conections and handles them to ChatServerConnections.
*/ public void run() { try { this.socketServer = new ServerSocket(this.port); this.listening = true; debug("listening"); while (listening) { Socket socket = this.socketServer.accept(); debug("client connection from " + socket.getRemoteSocketAddress()); ChatServerConnection socketConnection = new ChatServerConnection(socket, this); socketConnection.start(); this.clientConnections.add(socketConnection); }; } catch (Exception e) { debug(e.getMessage()); } } /**
* Broadcasts a message to all the clients.
*
* @param msg the message to be sent
*/ public void writeToAll(String msg) { try { for (int i = 0; i < this.clientConnections.size(); i++) { ChatServerConnection client = this.clientConnections.get(i); client.write(msg); } debug("broadcast message '" + msg + "' was sent"); } catch (Exception e) { debug("Exception (writeToAll): " + e.getMessage()); } } /**
* Removes a client from the server (it's expected that the client closes its own connection).
*
* @param remoteAddress the remote address of the client's socket connection
* @return true if the client was successfully removed
*/ public boolean remove(SocketAddress remoteAddress) { try { for (int i = 0; i < this.clientConnections.size(); i++) { ChatServerConnection client = this.clientConnections.get(i); if (client.getRemoteAddress().equals(remoteAddress)) { this.clientConnections.remove(i); debug("client " + remoteAddress + " was removed"); writeToAll(remoteAddress + " has disconnected."); return true; } } } catch (Exception e) { debug("Exception (remove): " + e.getMessage()); } return false; } }
Muito simples. Quando queremos remover um cliente dizemos aos outros que cliente se desligou. É da responsabilidade da classe ChatServerConnection terminar a ligação com o cliente, depois deste ser removido. Não fazemos isto no método remove.
Na classe ChatServerConnection simplesmente esperamos por uma mensagem do cliente. Se corresponder a "quit" desligaremos esse cliente. Vamos também fazer um método write para enviar mensagens para o cliente.
Aqui fica o código para a classe ChatServerConnection:
public class ChatServerConnection extends Thread { protected Socket socket; protected BufferedReader socketIn; protected PrintWriter socketOut; protected ChatServer server; /*
* Creates a new instance of ChatServerConnection.
*
* @param socket the client's socket connection
* @param server the server to each the client is connected
**/ public ChatServerConnection(Socket socket, ChatServer server) { this.socket = socket; this.server = server; } /**
* Waits from messages from the client and then instructs the server to send the messages to all clients.
*/ public void run() { try { this.socketIn = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); this.socketOut = new PrintWriter(this.socket.getOutputStream(), true); this.server.writeToAll(this.getRemoteAddress() + " has connected."); String line = this.socketIn.readLine(); while (line != null) { debug("client says '" + line + "'"); // If it's a quit command, we remove the client from the server and exit if (line.compareToIgnoreCase("quit") == 0) { if (this.server.remove(this.getRemoteAddress())) { this.finalize(); return; } } this.server.writeToAll(this.getRemoteAddress() + ": " + line); line = this.socketIn.readLine(); } } catch (Exception e) { debug("Exception (run): " + e.getMessage()); } } /**
* Sends a message to the connected party.
*
* @param msg the message to send
*/ public void write(String msg) { try { this.socketOut.write(msg + "u0000"); this.socketOut.flush(); } catch (Exception e) { debug("Exception (write): " + e.getMessage()); } } }
Nunca é demais dizer que estes são apenas os métodos principais. Para o código completo vejam o código fonte.
Acabamos a funcionalidade do servidor, mas vamos ainda fazer mais no capítulo seguinte.
Construir a interface e fazer uma aplicação de teste
O último passo a fazer no servidor é ligar tudo e construir uma interface para que possamos ver o que está a acontecer. Vamos precisar de 2 classes para isto:
- ChatServerGUI: fornece a interface para uma melhor experiência de teste
- Main: a classe principal da aplicação, responsável por construir ambos os servidores
A classe ChatServerGUI é um simples JFrame com uma JLabel para mostrar o número de clientes e uma JTextArea para mostrar mensagens de depuração.
Também usamos uma TimeTask para actualizar o número de clientes ligados. Isto é fácil de fazer, mas está fora do âmbito deste tutorial. Vejam o código fonte sobre como fazer isto.
A classe ChatServerGUI apenas tem um método: write. Este método é usado para escrever mensagens de depuração. É definida da seguinte forma:
/**
* Writes a message to the text area of the form.
*
* @param msg the message to be written.
*/
public void write(String msg) {
try {
this.debugTextArea.getDocument().insertString(0, msg + "n", null);
}
catch (Exception e) {
}
}
Não há muito mais nesta classe. Agora vamos tratar da classe Main. Esta classe vai criar tanto o servidor de política como o servidor de chat e ainda a interface.
Este é o código para o seu método main:
public static void main(String[] args) {
try {
int chatPort = 5555;
int policyPort = chatPort + 1;
for (int i = 0; i < args.length; i++) {
if (i == 0) {
chatPort = Integer.parseInt(args[i]);
}
if (i == 1) {
policyPort = Integer.parseInt(args[i]);
}
}
PolicyServer policyServer = new PolicyServer(policyPort);
policyServer.start();
ChatServer chatServer = new ChatServer(chatPort);
chatServer.start();
ChatServerGUI gui = new ChatServerGUI(chatServer);
gui.setTitle("ChatServer");
gui.setLocationRelativeTo(null);
gui.setVisible(true);
}
catch (Exception e) {
debug("Main", "Exception (main)" + e.getMessage());
}
}
É basicamente isto.
Testar a aplicação de chat
Finalmente chegamos à parte divertida!
Comecem por executar a aplicação servidora. Esta precisa de ser a primeira a ser executada. Só depois é que os clientes se podem ligar a esta.
Agora, para uma última correcção. Como no meu caso preciso de testar a aplicação localmente, tive de mudar as definições nas Global Security Settings do meu Flash Player. Isto não deverá ser preciso quando corremos o Flash remotamente. Precisamos de dar permissões ao nosso ficheiro Flash.
O controlo Flash Settings Manager encontra-se na web. Abram o vosso Flash Settings Manager. Deverá abrir na divisão Global Security Settings. Agora adicionem a localização do vosso ficheiro Flash.

Eu sei, é uma chatice! A mensagem que mostram também não faz muito sentido - estamos a usar as últimas capacidades do ActionScript e do Flash, não métodos antigos!
Finalmente, executem os vossos clientes e boa conversação!
Fica aqui uma imagem do servidor a correr.

Agora, uma imagem do cliente chat.

Recursos
Comentários
01:02 01-12-2008pu-c
Heureka! I've been searching for hours now and finally, there is it! thanks thanks thanks06:56 13-12-2008krishsal
jhio07:00 13-12-2008krishsal
Hi,its working from Flash Compile time but its not working from the HTML file.. what could be the problem.. is XMLSockets work on the browser or else we should go for Javascript for the communication..07:01 13-12-2008krishsal
Please help me this is very urgent.. My complete project depending upon the communication between flash and java.. thanks in advance..11:58 13-12-2008ZappyAd
Great tutorial - but, I can't get the security fix working on vista 64b bit. I have set up the flash player settings as directed but still get the local files can't use sockets error. Do I need to do something else?20:23 27-12-2008Hugo
How do you make a comment appliction... LIKE THIS lol, but seriously...17:32 03-01-2009nunof
Thank you all for your comments.@ krishsal: Sorry for the late response, make sure you did all the steps mentioned in this tutorial.
@ ZappyAd: I tested this on a Vista 64bit environment, so the OS should not be the problem. Are you sure you did all the steps mentioned in the tutorial?
@ Hugo: What do you mean? Please be more specific.
21:06 05-01-2009Rogier
Now THATS a tutorial!18:20 07-01-2009Peter
Wow, this is awesome, thanks for the tutorial :)17:22 08-01-2009Chad
Great tutorial! It's nice to see someone implement the policy server in Java as opposed to Perl/Python.When I run a Flash app that uses sockets in Adobe Flash using Ctr+Enter, it connects perfectly. But when I try creating a socket connection when running it remotely, the server connects and disconnects in about 3 seconds. I currently have a call to the loadPolicyFile function with "http://ipaddress/crossdomain.xml" and host the file, but it doesn't work. So hopefully using Security.loadPolicyFile("xmlsocket://" + ipAddress + ":" + policyPort); and setting up a policy server will fix my problem.
* Does anyone else think this policy stuff is a bit over the edge? I can create a java applet that establishes a socket connection without a policy file.
07:07 14-01-2009Chad
Sweet... loading the policy file works great when I use the smlsocket:// request. Nice tutorial. =)FYI... maybe this is common knowledge. But when you create an event handler for a ProgressEvent.SocketData, but you're only using mySocket.readUTF();... it is possible that there is a queue of messages waiting for you and you might have to read two or three strings each time the event handler is called.
In my situation, my server sends two string messages almost simultaneously after a user logs on. I figured the ProgressEvent handler would fire twice, but it doesn't. I had to do:
while (mySocket.dataAvailable > 0) {
var msg:String = mySocket.readUTF();
...
}
04:28 15-01-2009James
In the Chat Server Connection Class at the end of the file you have "this.socketOut.write(msg + "u0000"); ". What is the purpose of the u0000?I've been having trouble with my socket server, if I send nonsense I correctly receive the "malformed policy file" warning, but If I send the policy file you have listed above, my client times out after 3 seconds while "waiting for socket policy file".
My guess is I'm missing a terminator at the end of the policy file.
16:30 19-01-2009AndyCook
Hi,This tutorial looks great. I am trying to get the files you provided working on my server and when I try to compile the java classes using "javac FileName.java", I get errors saying something like:
PolicyServerConnection.java:65: cannot find symbol
symbol : variable PolicyServer
location: class chatserver.PolicyServerConnection
if (request.equals(PolicyServer.POLICY_REQUEST)) {
Is there a certain order you have to compile the files in? Or maybe I am just compiling everything wrong. Thanks a lot for your help
07:15 20-01-2009Chad
Hmmm... an interesting problem. I set up the server and client, and it works great using a browsers from a Windows PC or a system running Ubuntu... but it won't create a connection from a Mac running OS X.The client sends the Policy request to the server, the server replies and clears the policy connection. But then the real connection never establishes itself.
Anyone else have this problem?
10:15 02-02-2009MOHAMMAD
Thanks for this tutorial. it's great and helps a lot. i hop Adobe doesn't comes up with new flash Player :)any way i need to change my server program . I looking forward for your new tutorials.
11:50 11-03-2009Filip
I would just like to say, great job & thx! Spent quite some time trying to pull this of on my own and then I find this fantastic tutorial :)08:45 05-07-2009Rick_Winscot
With regard to the Mac OS X problem... if you are setting up your policy server on port 843 or any port below 1024 - these are considered 'privileged ports.' Any bind will fail unless the process is started as root. Workarounds include but are not limited to: commons-daemon, jsvc, some fancy scripts, chown, or pixie dust.20:41 13-08-2009Michael
Hi, I have written the as you have it here and there is only one error int the next line:String request = read();
who belongs the read() method to? I thought it belongs to the instance socketIn but this hasn't this method.
Thanks in advance and great tutorial, i have been looking for one of this kind for to long.
22:44 14-08-2009nunof
The read() method belongs to the PolicyServerConnection class. It was omitted for brevity.You can get the complete source code at http://www.broculos.net/files/articles/FlashJavaChat/FlashJavaChat.rar.
00:23 16-08-2009Durnus
If I'm not mistaken, it's a null character. See wikipedia here: http://en.wikipedia.org/wiki/Null_characterFlash requires all data from sockets to be ended in a null character, so that's probably why it's there.
>By: James
>In the Chat Server Connection Class at the end of >the file you have "this.socketOut.write(msg + >"u0000"); ". What is the purpose of the u0000?
02:52 25-08-2009Brokkoli
thank you. great work :)16:07 28-08-2009JuniorL
Muito bom, valew ae!abraços...
15:56 18-09-2009david
hello. I would like to ask you for help. I am looking for a live chat support. Example: i have approx. 150 operators. Each operator needs to have its own chat room (window chat) so other users can directly communicate with him. So if i have 150 operators i need 150 different chats windows (rooms). Do you think this is possible deploy using flash and xml socket server? thank you very much for your help! david19:00 19-09-2009nunof
Hi David,A Flash and Java solution should be able to deal with that.
But you can easily make a test scenario, by downloading the source code of this tutorial and making some adjustments to your needs.
12:28 26-09-2009Eero
Hi!I try to do something similar on Mac on localhost and it seems that if I put the swf in trusted location it did not need any policy file at all but outside trusted location I get request for policy file, send it and then connection just times out and I get security violation error.
Now I tried Your application (made some minor changes for working on Mac) and same problem - from outside trusted location swf don't get policy file and no connection.
03:48 28-09-2009Shenglong
hi great tutorial, been looking for one like this for ages :)just one question, how would i assign unique id numbers to all the clients who connect and then remove when they disconnect ?
13:11 28-09-2009Eero
Hi.I read from official documentation that there is some differences on localhost but as I now understand Flash player don't accept policy file on localhost.
15:11 10-10-2009Cander
Thank you!http://javaforums.smfforfree3.com/index.php
00:15 20-10-2009Ric01
Hey nunof! Great tutorial! This is awesome! Thank you for posting it!Question: Is this meant to only be used as a model for other programmers who are looking to make their own chat servers and clients, or can this code that you have written and provided here be freely used for any purpose? In other words, if I'm making my own chat program, do you mind if I use and modify the Flash/Actionscript and Java code that you have here?
Thanks!
-Ric
08:36 20-10-2009nunof
Hi Ric,Thanks for the comments.
You are free to do with the code whatever you want.
Good luck!
15:26 20-10-2009Ric01
Thank you, nunof!You've helped me out a lot!
Best,
Ric
04:40 27-10-2009Ric01
Hey again, nunof!Another question for you: Any idea how to automatically make the dynamic text field scroll down when it's full of text? I've discovered that when you add a new line of text after filling up the text box, it jumps back up to the top line and makes it so the bottom-most text is not visible. Then you need to scroll down by clicking and dragging downward within the dynamic text box area.
Thanks!
-Ric
08:36 27-10-2009nunof
Hi Ric,Sorry, I don't know. I haven't developed on Flash for some time.
Maybe it's one of the properties of the text field.
21:39 27-10-2009Ric01
Good news! I've got it working!I added one line to your receiveData function in ChatClient.as.
private function receiveData(msg:String):void {
trace("Message received: " + msg);
this.chatArea.appendText(msg + "\n");
this.chatArea.scrollV = this.chatArea.maxScrollV;// This is the new line that I added - This will scroll the text down automatically to the bottommost line as new text is added.
}
Hopefully someone else can benefit from this addition!
-Ric
15:12 25-11-2009Omni
Great tutorial! Made it work.One question though, is it possible to send objects instead of just a string?
That way i can sent multiple variables at once.
16:29 25-11-2009nunof
@Omni: For that purpose you can try serializing objects before sending them and then deserializing them when receiving.But you have to use the same technique to serialize/deserialize on both ends, of course.
20:21 26-11-2009Omni
heh, that's the part where i got stuck, im not sure how to serialize them so they can read each other. when i just send the flash object over the server gets the error "invalid stream header: 0609686F". There is so little info on google about flash/java socket objects im starting to think it's not the common way to handle this.21:43 26-11-2009Omni
I made it work! was using ObjectOutputStream and bjectInputStream, but flash sends it as a string(serialized that is). Finally!22:53 26-11-2009nunof
Glad that you figured it out!17:18 17-01-2010Alexander
Great tutorial, but there is a few thing I dont understand!First:
It looks like the client are trying login on twice (both on your picture under "Here is a picture of the server running." and in real life at my computer. One of the logons work and the other is aborted.
I guess it aint a good practice to logon dobble.
Second:
At your function "writeToAllclient" I tried puting in "client.write("Count connections: " + this.clientConnections.size() );" to see how many connections the server got. I suspected that the server and I didnt agree.
When I connected two clients the server wrote "Count connections: 4" - wich is wrong.
I think that there is some problem with taht server and the counting of connections.
22:36 03-02-2010Alexander
It looks like you are making a double socket-connection:this.socket = new Socket(this.host, this.port);
this.socket.connect(this.host, this.port);
I think the first should be:
this.socket = new Socket();
Thx for a good tutorial.
15:34 04-02-2010Alexander
I think that you cant expect clients nicely to say 'quit' before loosing connection to the server.So I suggest to remake the run-function in ChatServerConnection to:
public void run() {
try {
socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
socketOut = new PrintWriter(socket.getOutputStream(), true);
server.writeToAll(getRemoteAddress() + " has connected.");
String line = socketIn.readLine();
while (line != null) {
debug("client says '" + line + "'");
server.writeToAll(getRemoteAddress() + ": " + line);
line = socketIn.readLine();
}
} catch (Exception e) {
debug("Exception (run): " + e.getMessage());
} finally {
try {
server.remove(getRemoteAddress());
} catch (Exception e) {
debug("Exception (run): " + e.getMessage());
}
finalize();
}
}
I think it would make it, so if clients drop the connection to the ChatServer then they will be removed from the list automatically.
15:55 04-02-2010nunof
Hi Alexander, thanks for your input again.I haven't tried what you suggested yet, but I don't think it will work that way.
To be able to detect a lost connection from a client, I think you will need to create a mechanism where it will ping the client every few seconds and see if it responds back and remove the connection when you don't get a response after a specific timeout.
12:58 13-02-2010sabereh
hi,Great tutorial!I'v a question about this.
i undrestood how send a public message by your tutorial,but how can i send a private message to spessial person ?
tnx again
10:08 14-02-2010nunof
Then you need to keep track of private chat sessions between users.You'll need to create more commands to initiate and leave private chat conversations and keep a channel open only between those users.
19:33 14-02-2010sabereh
hitnx for reply, but i need more guide,
how can i do : " keep a channel open only between those users" ?
20:49 14-02-2010nunof
I haven't researched that but obviously the server will have to keep track of what private conversations are going on and the client will need an additional window for each private conversation.Each time the client sends a message it needs to inform the server to who it is meant (if it's a private one). Then the server just sends it to that destination.
It's basically adding more layers to this demo, some more commands that the server will need to interpret and methods for private messaging (identifying the sender/receiver).
If you know how to program and work with Java and Flash and understand this tutorial, it shouldn't be that hard to build something more on top of this.
12:07 16-02-2010sabereh
thank you so much.14:14 27-02-2010salrod
Hi nunof, great tutorial!!i have a question to Omni... how you send the objects in flash? an another question, how you read in Java, those objects?
Thank you very much
10:38 28-02-2010Sabereh
hi nunof,i'm trying to put this line in block if ,becouse i need to display and send "abc" in flash:this.server.writeToAll(this.getRemoteAddress() + "abc"); (in chatserverconection.java)
but i can't.
then next ,trying to use public variable "u", and assign value to "u" in "block if" ,
and change this line to :
if(...)
{
u = "abc";
}
this.server.writeToAll(this.getRemoteAddress() + u);
but ,this not work ,and send null to flash.
can u help me plz?
best regrds.
10:55 28-02-2010nunof
Hi Sabereh,What do you mean by "block if"?
Where are you trying to put this code?
11:32 28-02-2010Sabereh
hi,tanx for your reply ,i change your code to :
public String u;
public void run() {
try {
this.socketIn = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.socketOut = new PrintWriter(this.socket.getOutputStream(), true);
this.server.writeToAll(this.getRemoteAddress() + "conect");
line =this.socketIn.readLine();
if (line != null) {
if (line.startsWith("HELOS"))
{
u ="~HI~2";
}
this.server.writeToAll(this.getRemoteAddress() +u); //IT SEND NULL TO DEBUG
// If it's a quit command, we remove the client from the server and exit
if (line.compareToIgnoreCase("\\quit") == 0) {
if (this.server.remove(this.getRemoteAddress())) {
this.finalize();
return;
}
}
}
}
TANX AGAIN .
11:51 28-02-2010nunof
First, you removed the while loop, so you will only get one message from the client.Also, the "u" string will only have something if the client says "HELOS".
You can use the "debug" method to write some debugging information on the server side.
12:19 28-02-2010Sabereh
hi,yes , you'r right .but i have to use this cod.becouse i need keep track conversation , but i couldn't do it in java code,then i manage private chat in flash by send and recieve flags.
in dbug ,"HELOS" recieved .but dont send to flash :~HI~2" .
what's your idea for access "u" ,in out of IF condition?
thank you
14:50 28-02-2010nunof
What does the client receive?17:29 28-02-2010Sabereh
hi ,i so thank you for your replys .this problem was solved.I had a mistake to typing "HELOS".I so sorry.
but i have an another problem again...
next handshaking above , i should to send a message in flash chat ... but conection closed and so it dosent send .it 's output:
ChatServer (5555): broadcast message '/127.0.0.1:43782~HI~200' was sent
ChatServer (5555): broadcast message '/127.0.0.1:43782conect' was sent
ChatServer (5555): client connection from /127.0.0.1:43782
PolicyServerConnection (/127.0.0.1:54857): connection closed
PolicyServerConnection (/127.0.0.1:54857): policy sent to client
PolicyServerConnection (/127.0.0.1:54857): client says ''
tanx
18:21 28-02-2010nunof
Doesn't that happen because you removed the while loop in the run method?14:14 01-03-2010Sabereh
hi nunof ,thanks alot for noticing that.
best regards
16:46 01-03-2010Rene
Hello, nice tutorial. Everything works fine... but I had troubles to compile it. Maybe some others had troubles also.Here's what I found to make it work:
javac -d . *.java
java chatserver.Main




17:19 30-09-2008jorgebucaran.com
Thanks for this tutorial. Very impressive.