Ajuda com envio e recebimento de arquivo e gerenciamento de clientes

Olá a todos. Sou novo no fórum, porém sempre o acompanhei. Estou com um projeto de chat em java, mas acabei encontrando algumas dificuldades. Procurei em muitos fóruns (inclusive aqui) porém minha dúvida não foi sanada.

Eu já estou conseguindo fazer o recebimento e envio de string via TCP. Ao tentar enviar o arquivo, gostaria de usar o mesmo fluxo já criado. Mas tentei inúmeros exemplos que vi em fóruns, mesmo adaptando não deu certo. A minha ideia seria enviar para o servidor e dele enviar para o outro usuário que eu gostaria. Porém, já modifiquei tanto este código que não consigo mais pensar numa solução.

O segundo problema. Tenho um ArrayList de usuário que se conectam no servidor. Eu varro esta lista e envio as mensagens para quem está conectado. Contudo, eu ainda preciso melhorar o gerenciamento desses usuários. Por exemplo, ao iniciar o usuário ele abre automáticamente a caixa de envio de mensagem. Eu consigo conectar vários clientes. Mas gostaria que o usuário pudesse ter uma lista desses clientes, deleta-los, adicioná-los, pudesse enviar apenas para um caso quisesse. Enfim, controlar essa lista.

Espero que alguém possa me ajudar. Fico no aguardo.

Grande abraço e muita paz.

// SERVIDOR



import java.io.*;
import java.net.*;
import java.util.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;

public class ServidorMsn {
	ArrayList clientesDoServidor;
	ServerSocket servidorSocket;
	
		public static void main(String[] args) {
			new ServidorMsn().go(); // Quando eu iniciar o servidor, ele chamará o método go
			//new ServidorMsn().TcpMsg();
			
			//new ServidorMsn().TcpMsg();
		}
		
		
		public void go(){
			  clientesDoServidor = new ArrayList(); // Crio a ArrayList onde estará a lista de clientes que meu servidor possui
			  String nome;
			
			  try{
				
				 servidorSocket = new ServerSocket(5000); // Crio um socket e associo a uma porta
				System.out.println("Servidor iniciado. Aguardando conexão... ");
				
				while(true){
					
					Socket socketCliente = servidorSocket.accept();
					PrintWriter escritor = new PrintWriter(socketCliente.getOutputStream());  
					clientesDoServidor.add(escritor); // Add o escritor a minha lista pois é ele que irá escrever meus clientes nela
					Thread t = new Thread (new AdmCliente(socketCliente)); // Crio uma Thread juntamente com um AdmCliente e associo ao socket
					t.start(); // Inicio a Thread
					System.out.println("Conexão estabelecida do Servidor! ");
					System.out.println("IP do Cliente conectado: " + 
							 ((InetSocketAddress)socketCliente.getRemoteSocketAddress()).getAddress().getHostAddress()
							 + " porta:  " + ((InetSocketAddress)socketCliente.getRemoteSocketAddress()).getPort());
					
				}
			}
			catch (Exception  e){
				
				System.out.println("Erro ao tentar iniciar o go() no servidor! ");
			}
				
		}
		
		// De forma analoga ao Cliente, aqui tem-se a parte de envio de arquivo.
		
		public void TcpMsg(){
			
			try{
				//ServerSocket servidor = new ServerSocket(5100); 
					
				
				while(true){	
				//Socket sv = servidor.accept(); 
		        //Socket socketArquivo = servidorSocket.accept();
		        
		        FileInputStream file = new FileInputStream("D:\\Work\\ServidorMsn\\Arquivos Enviados"); 
		        
		        ObjectInputStream obnoserver = new ObjectInputStream(file);
		        
		        obnoserver.readObject();
		        
		        System.out.println("Servidor iniciado. Aguardando conexão TcpMsg... ");
				
				}
			} 
	        //byte[] buf = new byte[4096]; 
	         
//	        while(true){ 
//	            int len = out.read(buf); 
//	            if(len == -1) break;         
//	            file.write(buf, 0, len); 
//	        		}
//				}
//			}
			catch (Exception  e){
				
				System.out.println("Erro classe TcpMsg.");
			}
	        
			}      
	
		
		
		
		public class AdmCliente implements Runnable{
			// Declaro variaveis para o leitor e para o socket, respectivamente.
			
			Socket socketServ;
			BufferedReader leitor;
			
			public AdmCliente (Socket socketCliente){
				
				try {
					// Abaixo, faço a associação dos sockets, crio um fluxo de leitura para o sevidor e crio um objeto leitor.
					socketServ = socketCliente;
					InputStreamReader leitorServ = new InputStreamReader(socketServ.getInputStream());
					leitor = new BufferedReader(leitorServ);
					}
				
				catch (Exception  e){
					
					System.out.println("Erro ao tentar ler! (no servidor)");
				}
			}// Fecha construtora
			
			public void run(){
				String mensagem;
				Object pasta;			
				
				try{
					// Quando a mensagem enviada for lida, caso esta mensagem não tenha valor nulo,
					//é enviado para todos a mensagem enviada (Inclusive para mim)
					while((mensagem = leitor.readLine())!= null){
						System.out.println("Leia:" + mensagem);
						enviarParaTodos(mensagem);
						System.out.println("Do cliente " + 
								 ((InetSocketAddress)socketServ.getRemoteSocketAddress()).getAddress().getHostAddress()
								 + ";" + "Porta:  " + ((InetSocketAddress)socketServ.getRemoteSocketAddress()).getPort());
					}
					
					
					while((Boolean)(pasta = leitor.readLine()!= mensagem)){
						
						
					}
				}
				catch (Exception  e){
					
					System.out.println("Erro ao tentar enviar a mensagem do servidor! ");
				}
			}
		} // Aqui fecha a classe Adm Cliente

		
		public void salvarArquivoComo (File pasta){
			
			try{
			PrintWriter  escritor = new PrintWriter(pasta); 
			escritor.println("D:\\Work\\ServidorMsn\\Arquivos Enviados");
			escritor.flush(); 
			}
			
			catch (Exception  e){
				
				System.out.println("Erro ao tentar salvar arquivo no Servidor!");
			}
		}
		
		public void enviarParaTodos(String mensagem){
			
			Iterator  i = clientesDoServidor.iterator(); // O iterator varre a minha lista de forma sequencial
			
			while(i.hasNext())// i.hasNext retorna true se o iterator tem mais elementos a serem "varridos"
				{
				try{
					// Caso possua mais elementos, eu crio um escritor e uso este para imprimir a mensagem para cada elemente que o iterator varrer
					PrintWriter  escritor = (PrintWriter)i.next(); 
					escritor.println(mensagem);
					escritor.flush(); //Flush garante o envio do ultimo pacote de dados, forçando a escrita desses dados que estão no buffer
				}
				catch (Exception  e){
					
					System.out.println("Erro ao tentar enviar a mensagem para todos os clientes no servidor!");
				}
			}
			
		}
		
			
}
// CLIENTE



import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.*;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class Cliente2 {

	JTextField saidaMsg;
	JTextField nomeDaConversa;
	JTextArea textoRecebido;
	BufferedReader leitor; 
	PrintWriter escritor;
	BufferedWriter bw = null;
	FileWriter f;
	File arquivo;
	JFileChooser enviarArquivo;
	Socket socket;
	InputStreamReader fluxoDeLeitura;
	OutputStream fluxoDearquivo;

	
	public static void main(String[] args) {
		
		Cliente2 cliente = new Cliente2();  // Crio um novo Cliente
		cliente.janelaGrafica(); // Instancio um novo cliente chamando a interface do msn
		
	}

	private void janelaGrafica(){      
		
		JFrame janelaPrincipal = new JFrame("Janela do Fulano"); // Crio a janela
		JPanel painelPrincipal = new JPanel();// Insiro um painel
		
		// Aqui, crio uma area de texto, não editável pelo usuário e podendo ter quebra de letras e linhas
		textoRecebido = new JTextArea(20, 45); 
		textoRecebido.setLineWrap(true);
		textoRecebido.setWrapStyleWord(true);
		textoRecebido.setEditable(false);
		
		JScrollPane barraRolagem = new JScrollPane(textoRecebido); // Add barra de rolagem à minha àrea de texto
		barraRolagem.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); //Seto barras de rolagens verticais e horizontais 
		barraRolagem.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		saidaMsg = new JTextField(40);//Crio um campo de texo com tamanho 40 de colunas
		
		JButton botaoEnviar = new JButton("Enviar"); //Crio o botão
		botaoEnviar.addActionListener(new BotaoDeEnviar()); // Add a ação ao botão, chamando a classe botaoDeEnviar e assim, seus respectivos métodos
		botaoEnviar.setBounds(650, 354, 124, 57);// Estabeleço as coordenadas do botão 
		
		JButton botaoEnviarArquivo = new JButton("Enviar Arquivo"); //Crio o botão para enviar arquivo
		botaoEnviarArquivo.addActionListener(new BotaoEnviarArquivo());
		botaoEnviarArquivo.setBounds(250, 374, 124, 57);
		
		JButton botaoSalvarConversa = new JButton("Salvar Conversa"); //Crio o botão para salvar conversa
		botaoSalvarConversa.addActionListener(new BotaoSalvarConversa());
		botaoSalvarConversa.setBounds(450, 374, 124, 57);
		
		painelPrincipal.add(barraRolagem); // Add a barra de rolagem ao painel
		painelPrincipal.add(saidaMsg);  // Add o text field ao painel
		painelPrincipal.add(botaoEnviar); // Add o botão no painel
		painelPrincipal.add(botaoEnviarArquivo);
		painelPrincipal.add(botaoSalvarConversa);
//		painelPrincipal.add(botaoFecharConversa);
		
		conexaoClienteServidor(); // Chamo o método para realizar a conexão TCP entre cliente e servidor
		
		// Inicio aqui a thread cliente, que chama uma classe interna. Esta tem como função ler o fluxo do socket do servidor e exibir qualquer msg na textArea
		Thread threadCliente = new Thread(new LeitorDeEntrada()); 
		threadCliente.start();
		
		janelaPrincipal.getContentPane().add(BorderLayout.CENTER, painelPrincipal); //  getContentPane() retorna o painel principal da JPanel
		janelaPrincipal.setBounds(100,100,600,500);
		janelaPrincipal.setVisible(true);
		
		
	}
	
	public void conexaoClienteServidor(){
		
		try
		{
			// Crio o Socket e add porta e Ip
			socket = new Socket("127.0.0.1", 5000);
						
			// Crio o fluxo de leitura (de entrada, obviamente) do cliente
			InputStreamReader fluxoDeLeitura = new InputStreamReader(socket.getInputStream()); 			
			leitor = new BufferedReader(fluxoDeLeitura);// Aqui passo a variavel leitor do tipo buffreader e digo que ela esta no fluxo de leitura
			
			escritor = new PrintWriter(socket.getOutputStream()); 
			
			System.out.println("Conexão do cliente 2 bem sucedida! ");
		}
		catch(Exception e)
		
		{
			System.out.println("Erro na conexão!");
		}
		
		
			
	}
	
//	public void conexãoTcpArquivo(){
//		try{
//			
//			//Socket socket = new Socket("127.0.0.1",5100);
//			ObjectInputStream saidaArquivo = new ObjectInputStream(socket.getInputStream());
//			 
//		}
//		catch (Exception  e)
//		{
//			System.out.println("Erro ao tentar enviar o arquivo3 ");
//		}
//		
//	}
//	
	public class BotaoDeEnviar implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			try{
				// Aqui pega-se o texto da saidaMsg(textField) e, através do escritor, imprime a msg no fluxo para o servidor
				escritor.println(saidaMsg.getText()); 
							
				escritor.flush();//Flush garante o envio do ultimo pacote de dados, forçando a escrita desses dados que estão no buffer
			}
			
			catch (Exception  e)
			{
				System.out.println("Erro ao tentar enviar a mensagem! ");
			}
			
			saidaMsg.setText("");
			saidaMsg.requestFocus();// Captura eventos do mouse, como o clique à um textField
		}

	}
	
	// A partir daqui, tem- se a implementação quase pronta para enviar um arquivo. 
	
	public class BotaoEnviarArquivo implements ActionListener{
		
		public void actionPerformed(ActionEvent arg0) {
			
			try{
				//BotaoEnviarArquivo bea = new BotaoEnviarArquivo();
				//bea.conexaoTcpArquivo();
				
				enviarArquivo = new JFileChooser();
				int result = enviarArquivo.showOpenDialog(null);
				
				if (result == JFileChooser.CANCEL_OPTION){
					
					System.out.println("Erro ao tentar enviar o arquivo.");
				}
				
				else {
					
					File pasta = enviarArquivo.getSelectedFile();
//					FileOutputStream pastaDeSaida = new FileOutputStream(enviarArquivo.getSelectedFile());
//					ObjectOutputStream obarquivo = new ObjectOutputStream(pastaDeSaida);
//					 fluxoDearquivo = obarquivo;	
//					fluxoDearquivo.printWriter(pastaDeSaida);
//					
					escritor = new PrintWriter(socket.getOutputStream()); 
					escritor.println(pasta);
					escritor.flush();
//					byte[] buf = new byte[4096]; 
//			         
//			        while(true){ 
//			            int len = file.read(buf); 
//			            if(len == -1) break; 
//			            saidaArquivo.write(buf, 0, len); 
//			        } 
					
					 
			         
				}
				
			}
			
			catch (Exception  e)
			{
				System.out.println("Erro ao tentar enviar o arquivo (Excessão). ");
			}
			
		}
		
		
	}
	
	public class BotaoSalvarConversa implements ActionListener{
				
		public void actionPerformed(ActionEvent arg0) {
						
			try{
				BotaoSalvarConversa bsc = new BotaoSalvarConversa();
				bsc.janelaSalvarConversa();		
			}
			
			catch (Exception  e)
			{
				System.out.println("Erro ao tentar salvar a conversa em .txt ");
			}
			
		}
		
		public void janelaSalvarConversa(){
			//Inicio da janela de opção para salvar a conversa
			JFrame janelaDeSalvar = new JFrame ("Coloque o nome do arquivo...");
				
			JPanel painelDeSalvar = new JPanel();
			nomeDaConversa = new JTextField(10);
			
			JButton salvarNomeConversa = new JButton("Salvar Conversa!");
			salvarNomeConversa.setBounds(250, 374, 124, 57);
			
			//JButton cancelarNomeConversa = new JButton("Cancelar");
			
			painelDeSalvar.add(nomeDaConversa);
			painelDeSalvar.add(salvarNomeConversa);
			//painelDeSalvar.add(cancelarNomeConversa);
			
			janelaDeSalvar.getContentPane().add(BorderLayout.CENTER, painelDeSalvar); //  getContentPane() retorna o painel principal da JPanel
			janelaDeSalvar.setBounds(100,100,300,150);
			janelaDeSalvar.setVisible(true);
			
			salvarNomeConversa.addActionListener(new SalvarNomeConversa());
			
		}
	}
	
	public class SalvarNomeConversa implements ActionListener{
	
		public void actionPerformed(ActionEvent arg0) {
			try{
							
				nomeDaConversa.getText();
				System.out.println(	nomeDaConversa.getText());
				arquivo = new File("D:\\Work\\ProjetoMsn\\Conversas Salvas 2\\" + nomeDaConversa.getText() + ".txt"); 
				bw = new BufferedWriter(new FileWriter(arquivo, true));
				textoRecebido.write(bw);
				bw.close();			
				
			}
			catch (Exception  e)
			{
				System.out.println("Erro ao tentar salvar a conversa em .txt na classe SalvarNomeConversa");
			}
			
		}
		
	
	}
	
	public class LeitorDeEntrada implements Runnable {
		
		public void run(){
			
			String mensagem;
			
			try{
				// Aqui ele permanece em loop enquanto o que estiver capturando no servidor não ter valor nulo
				while((mensagem = leitor.readLine())!= null) {
					
					System.out.println("Leu:" + mensagem);
					textoRecebido.append( "Fulano: " + "\n"+ mensagem + "\n");// Pega o texto que o servidor enviou (texto lido, ou recebido) e inseri no textArea
				}
			}
			
			catch (Exception  e)
			{
				System.out.println("Erro ao tentar iniciar a thread do cliente! ");
			}
		}
	}
	
	
}


#medo

Alguém disponível?