578 lines
17 KiB
Java
578 lines
17 KiB
Java
package chat;
|
||
|
||
import java.net.*;
|
||
|
||
import javax.swing.*;
|
||
|
||
import java.awt.*;
|
||
import java.util.List;
|
||
import java.awt.event.*;
|
||
|
||
import java.io.*;
|
||
import java.util.*;
|
||
|
||
import chat.User;
|
||
import chat.Message;
|
||
|
||
class OutdoorListenerThread extends Thread {
|
||
User user;
|
||
JTextArea displayArea;
|
||
JTextArea knownUsersPanel;
|
||
List<User> known_users;
|
||
List<Socket> dest_sockets;
|
||
List<Socket> outdoor_dest_sockets;
|
||
int portNumber;
|
||
|
||
OutdoorListenerThread(User in_user, List<User> in_known_users, List<Socket> in_dest_sockets, List<Socket> in_outdoor_dest_sockets,
|
||
JTextArea in_displayArea, JTextArea in_knownUsersPanel)
|
||
{
|
||
user = in_user;
|
||
known_users = in_known_users;
|
||
dest_sockets = in_dest_sockets;
|
||
outdoor_dest_sockets = in_outdoor_dest_sockets;
|
||
displayArea = in_displayArea;
|
||
knownUsersPanel = in_knownUsersPanel;
|
||
portNumber = 2344;
|
||
}
|
||
public void run()
|
||
{
|
||
boolean exit = false;
|
||
boolean accepted = true;
|
||
byte[] buffer = new byte[100];
|
||
|
||
|
||
String username;
|
||
String response = "";
|
||
|
||
byte[] responseBytes;
|
||
try
|
||
{
|
||
while(!exit)
|
||
{
|
||
try
|
||
{
|
||
System.out.println("Waiting for connection request");
|
||
ServerSocket servSocket = new ServerSocket(1234);
|
||
Socket link = servSocket.accept();
|
||
BufferedReader in = new BufferedReader(new InputStreamReader(link.getInputStream()));
|
||
PrintWriter out = new PrintWriter(link.getOutputStream(), true);
|
||
username = in.readLine();
|
||
System.out.println("Received a request from " + username + "@" + link.getRemoteSocketAddress().toString());
|
||
|
||
response = "";
|
||
for(User u:known_users)
|
||
{
|
||
response += u.getName() + " ";
|
||
}
|
||
response = response.trim();
|
||
response += ";";
|
||
for(Socket s:dest_sockets)
|
||
{
|
||
response += s.getInetAddress().getHostAddress() + " ";
|
||
}
|
||
response = response.trim();
|
||
response += ";" + (portNumber+1);
|
||
|
||
out.println(response);
|
||
|
||
accepted = true;
|
||
for(User a:known_users)
|
||
{
|
||
accepted = accepted && (!username.equals(a.getName()));
|
||
}
|
||
if(accepted)
|
||
{
|
||
portNumber++;
|
||
Socket s = (new ServerSocket(portNumber)).accept();
|
||
(new ReceiveThread(user, s, displayArea, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start();
|
||
outdoor_dest_sockets.add(s);
|
||
|
||
known_users.add(new User(username));
|
||
|
||
Collections.sort(known_users);
|
||
|
||
displayArea.append(username + " has joined the chat.\n");
|
||
displayArea.setCaretPosition(displayArea.getDocument().getLength());
|
||
knownUsersPanel.setText("");
|
||
knownUsersPanel.append("Online:\n");
|
||
for(User a:known_users)
|
||
{
|
||
knownUsersPanel.append(" " + a.getName() + " \n");
|
||
}
|
||
}
|
||
}
|
||
catch(SocketTimeoutException e) {}
|
||
}
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
e.printStackTrace();
|
||
System.out.println(e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
class ReceiveThread extends Thread {
|
||
User user;
|
||
Socket socket;
|
||
JTextArea displayArea;
|
||
JTextArea knownUsersPanel;
|
||
Boolean isOutdoor;
|
||
List<User> known_users;
|
||
List<Socket> dest_sockets;
|
||
List<Socket> outdoor_dest_sockets;
|
||
|
||
ReceiveThread(User in_user, Socket in_socket, JTextArea in_displayArea, List<User> in_known_users, JTextArea in_knownUsersPanel,
|
||
List<Socket> in_dest_sockets, List<Socket> in_outdoor_dest_sockets, Boolean in_isOutdoor)
|
||
{
|
||
user = in_user;
|
||
socket = in_socket;
|
||
displayArea = in_displayArea;
|
||
knownUsersPanel = in_knownUsersPanel;
|
||
known_users = in_known_users;
|
||
dest_sockets = in_dest_sockets;
|
||
outdoor_dest_sockets = in_outdoor_dest_sockets;
|
||
isOutdoor = in_isOutdoor;
|
||
}
|
||
public void run()
|
||
{
|
||
boolean exit = false;
|
||
try
|
||
{
|
||
while(!exit)
|
||
{
|
||
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
|
||
Message message = (Message) in.readObject();
|
||
if(message.getText() != null)
|
||
{
|
||
displayArea.append(message.getAuthor() + " : " + message.getText() + "\n");
|
||
|
||
}
|
||
else
|
||
{
|
||
displayArea.append(message.getAuthor() + " has left the chat.\n");
|
||
for(int i = 0;i < known_users.size();i ++)
|
||
{
|
||
|
||
if (known_users.get(i).getName().equals(message.getAuthor()))
|
||
{
|
||
known_users.remove(i);
|
||
break;
|
||
//System.out.println("Removing " + message.getAuthor());
|
||
}
|
||
}
|
||
knownUsersPanel.setText("");
|
||
knownUsersPanel.append("Online:\n");
|
||
for(User u:known_users)
|
||
{
|
||
knownUsersPanel.append(" " + u.getName() + " \n");
|
||
}
|
||
if(!message.getAuthor().equals(user.getName()))
|
||
{
|
||
socket.close();
|
||
if(!isOutdoor)
|
||
dest_sockets.remove(socket);
|
||
else
|
||
outdoor_dest_sockets.remove(socket);
|
||
}
|
||
exit = true;
|
||
}
|
||
|
||
displayArea.setCaretPosition(displayArea.getDocument().getLength());
|
||
if(isOutdoor)
|
||
{
|
||
for(Socket s:dest_sockets)
|
||
{
|
||
try
|
||
{
|
||
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
|
||
out.writeObject(message);
|
||
}
|
||
catch(IOException e){}
|
||
}
|
||
}
|
||
|
||
for(Socket s:outdoor_dest_sockets)
|
||
{
|
||
try
|
||
{
|
||
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
|
||
out.writeObject(message);
|
||
}
|
||
catch(IOException e){}
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
catch(EOFException e) {}
|
||
catch(Exception e)
|
||
{
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
|
||
class ConnectionListenerThread extends Thread {
|
||
User user;
|
||
JTextArea displayArea;
|
||
JTextArea knownUsersPanel;
|
||
List<User> known_users;
|
||
List<Socket> dest_sockets;
|
||
List<Socket> outdoor_dest_sockets;
|
||
int portNumber;
|
||
|
||
ConnectionListenerThread(User in_user, List<User> in_known_users, List<Socket> in_dest_sockets, List<Socket> in_outdoor_dest_sockets,
|
||
JTextArea in_displayArea, JTextArea in_knownUsersPanel, int in_portNumber)
|
||
{
|
||
user = in_user;
|
||
known_users = in_known_users;
|
||
dest_sockets = in_dest_sockets;
|
||
outdoor_dest_sockets = in_outdoor_dest_sockets;
|
||
displayArea = in_displayArea;
|
||
knownUsersPanel = in_knownUsersPanel;
|
||
portNumber = in_portNumber;
|
||
}
|
||
public void run()
|
||
{
|
||
boolean exit = false;
|
||
boolean accepted = true;
|
||
byte[] buffer = new byte[100];
|
||
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
|
||
DatagramPacket responsePacket;
|
||
|
||
DatagramSocket requestSocket;
|
||
DatagramSocket responseSocket;
|
||
|
||
String username;
|
||
String response = "";
|
||
|
||
byte[] responseBytes;
|
||
try
|
||
{
|
||
requestSocket = new DatagramSocket(1234);
|
||
responseSocket = new DatagramSocket();
|
||
|
||
while(!exit)
|
||
{
|
||
try
|
||
{
|
||
System.out.println("Waiting for connection request");
|
||
requestSocket.receive(request);
|
||
username = new String(request.getData(), 0, request.getLength());
|
||
|
||
InetAddress clientAddress= request.getAddress();
|
||
System.out.println("Received a request from " + username + "@" + clientAddress.getHostAddress());
|
||
|
||
response = "";
|
||
for(User u:known_users)
|
||
{
|
||
response += u.getName() + " ";
|
||
}
|
||
response = response.trim();
|
||
response += ";";
|
||
for(Socket s:dest_sockets)
|
||
{
|
||
response += s.getInetAddress().getHostAddress() + " ";
|
||
}
|
||
response = response.trim();
|
||
response += ";" + (portNumber+1);
|
||
|
||
System.out.println("Response :" + response);
|
||
responseBytes = response.getBytes();
|
||
responsePacket = new DatagramPacket(responseBytes, responseBytes.length, clientAddress, 1337);
|
||
responseSocket.send(responsePacket);
|
||
|
||
accepted = true;
|
||
for(User a:known_users)
|
||
{
|
||
accepted = accepted && (!username.equals(a.getName()));
|
||
}
|
||
if(accepted)
|
||
{
|
||
portNumber++;
|
||
Socket s = (new ServerSocket(portNumber)).accept();
|
||
(new ReceiveThread(user, s, displayArea, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start();
|
||
dest_sockets.add(s);
|
||
|
||
|
||
known_users.add(new User(username));
|
||
|
||
Collections.sort(known_users);
|
||
|
||
displayArea.append(username + " has joined the chat.\n");
|
||
displayArea.setCaretPosition(displayArea.getDocument().getLength());
|
||
knownUsersPanel.setText("");
|
||
knownUsersPanel.append("Online:\n");
|
||
for(User a:known_users)
|
||
{
|
||
knownUsersPanel.append(" " + a.getName() + " \n");
|
||
}
|
||
}
|
||
}
|
||
catch(SocketTimeoutException e) {}
|
||
}
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
e.printStackTrace();
|
||
System.out.println(e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
|
||
class ListenerStartThread extends Thread {
|
||
|
||
ServerSocket s;
|
||
List<Socket> dest_sockets;
|
||
ListenerStartThread(ServerSocket in_s, List<Socket> in_dest_sockets)
|
||
{
|
||
s = in_s;
|
||
dest_sockets = in_dest_sockets;
|
||
}
|
||
public void run()
|
||
{
|
||
try
|
||
{
|
||
dest_sockets.add(s.accept());
|
||
}
|
||
catch(IOException e) {}
|
||
}
|
||
}
|
||
|
||
public class NetworkClient {
|
||
private User user;
|
||
private List<User> known_users;
|
||
private List<Socket> dest_sockets;
|
||
private List<Socket> outdoor_dest_sockets;
|
||
private JTextArea chatText;
|
||
private JTextArea knownUsersPanel;
|
||
|
||
static String getLocalIP() {
|
||
String ip = "";
|
||
try(final DatagramSocket socket = new DatagramSocket()){
|
||
socket.connect(InetAddress.getByName("8.8.8.8"), 10002);
|
||
ip = socket.getLocalAddress().getHostAddress();
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
System.out.println("niiiiiiiikkk");
|
||
}
|
||
return ip;
|
||
}
|
||
|
||
NetworkClient(JTextArea in_chatText, JTextArea in_knownUsersPanel)
|
||
{
|
||
user = new User("");
|
||
chatText = in_chatText;
|
||
knownUsersPanel = in_knownUsersPanel;
|
||
known_users = new ArrayList<User>();
|
||
dest_sockets = new ArrayList<Socket>();
|
||
outdoor_dest_sockets = new ArrayList<Socket>();
|
||
}
|
||
|
||
boolean connect(String username, Boolean outdoor, String destinationIP)
|
||
{
|
||
boolean nameAvailable = true;
|
||
boolean connected = false;
|
||
DatagramSocket connectionSocket;
|
||
DatagramSocket userListSocket;
|
||
|
||
DatagramPacket connectionRequest;
|
||
DatagramPacket responsePacket;
|
||
|
||
String[] usernameList;
|
||
String[] addressList;
|
||
|
||
int portNumber = 1237;
|
||
byte[] buffer1 = new byte[20000];
|
||
|
||
if(username == null || username.compareTo("") == 0)
|
||
return false;
|
||
|
||
try
|
||
{
|
||
try
|
||
{
|
||
if(!outdoor)
|
||
{
|
||
connectionSocket = new DatagramSocket();
|
||
userListSocket = new DatagramSocket(1337);
|
||
|
||
userListSocket.setSoTimeout(500);
|
||
|
||
connectionRequest = new DatagramPacket(username.getBytes(), username.length(),
|
||
InetAddress.getByName(destinationIP), 1234);
|
||
/*l'adresse de broadcast est hardcod<6F>e ici
|
||
pour tester avec Hamachi, il faut la remplacer par celle du r<>seau local virtuel*/
|
||
System.out.println("Sending connection request");
|
||
connectionSocket.send(connectionRequest);
|
||
|
||
responsePacket = new DatagramPacket(buffer1, buffer1.length);
|
||
|
||
System.out.println("Waiting for reply");
|
||
userListSocket.receive(responsePacket);
|
||
System.out.println("Received a reply from " + responsePacket.getAddress().getHostAddress());
|
||
|
||
String[] response = new String(responsePacket.getData()).trim().split(";");
|
||
|
||
usernameList = response[0].split(" ");
|
||
addressList = response[1].split(" ");
|
||
portNumber = Integer.parseInt(response[2]);
|
||
|
||
connectionSocket.close();
|
||
userListSocket.close();
|
||
}
|
||
|
||
else
|
||
{
|
||
Socket requestSocket = new Socket(destinationIP, 1234);
|
||
BufferedReader in = new BufferedReader(new InputStreamReader(requestSocket.getInputStream()));
|
||
PrintWriter out = new PrintWriter(requestSocket.getOutputStream(), true);
|
||
out.println(username);
|
||
String[] response = in.readLine().split(";");
|
||
usernameList = response[0].split(" ");
|
||
addressList = new String[0];
|
||
portNumber = Integer.parseInt(response[2]);
|
||
requestSocket.close();
|
||
}
|
||
|
||
for(String u:usernameList)
|
||
{
|
||
nameAvailable = nameAvailable && (!username.equals(u));
|
||
}
|
||
if(nameAvailable)
|
||
{
|
||
System.out.println(usernameList.length + " users currently connected");
|
||
for(String u:usernameList)
|
||
{
|
||
known_users.add(new User (u));
|
||
}
|
||
for(String a:addressList)
|
||
{
|
||
Socket s = new Socket(a, portNumber);
|
||
dest_sockets.add(s);
|
||
(new ReceiveThread(user, s, chatText, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start();
|
||
}
|
||
Collections.sort(known_users);
|
||
connected = true;
|
||
}
|
||
}
|
||
catch(SocketTimeoutException e)
|
||
//Si on est tout seul sur le r<>seau (on ne re<72>oit aucune r<>ponse)
|
||
{
|
||
System.out.println("Reply timed out");
|
||
connected = true;
|
||
}
|
||
}
|
||
catch (SocketException e2)
|
||
{
|
||
e2.printStackTrace();
|
||
}
|
||
catch (Exception e3)
|
||
{
|
||
e3.printStackTrace();
|
||
}
|
||
|
||
if(connected)
|
||
{
|
||
if(!outdoor)
|
||
{
|
||
(new ConnectionListenerThread(user, known_users, dest_sockets, outdoor_dest_sockets, chatText, knownUsersPanel, portNumber)).start();
|
||
(new OutdoorListenerThread(user, known_users, dest_sockets, outdoor_dest_sockets, chatText, knownUsersPanel)).start();
|
||
|
||
try
|
||
{
|
||
ServerSocket s1 = new ServerSocket(portNumber);
|
||
(new ListenerStartThread(s1, dest_sockets)).start();
|
||
|
||
Socket s2 = new Socket(getLocalIP(), portNumber);
|
||
System.out.println(getLocalIP());
|
||
/*Attention, getLocalIP ne marche que sur un m<>me r<>seau physique
|
||
* pour tester avec Hamachi, il faut hardcoder les IP
|
||
*/
|
||
(new ReceiveThread(user, s2, chatText, known_users, knownUsersPanel, dest_sockets, outdoor_dest_sockets, false)).start();
|
||
}
|
||
catch(IOException e)
|
||
{
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
try
|
||
{
|
||
Socket s = new Socket(destinationIP, portNumber);
|
||
dest_sockets.add(s);
|
||
}
|
||
catch(IOException e)
|
||
{
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
user.setName(username);
|
||
known_users.add(new User(username));
|
||
Collections.sort(known_users);
|
||
|
||
chatText.append(username + " has joined the chat.\n");
|
||
chatText.setCaretPosition(chatText.getDocument().getLength());
|
||
|
||
knownUsersPanel.setText("");
|
||
knownUsersPanel.append(" Online :\n");
|
||
for(User a:known_users)
|
||
{
|
||
knownUsersPanel.append(" " + a.getName() + " \n");
|
||
}
|
||
}
|
||
|
||
return connected;
|
||
}
|
||
|
||
void send (String message)
|
||
{
|
||
System.out.println("Sending message");
|
||
System.out.println("Indoor users:");
|
||
for(Socket s:dest_sockets)
|
||
{
|
||
try
|
||
{
|
||
System.out.println(s.getInetAddress().getHostAddress() + ": local port " + s.getLocalPort() + ", remote port " + s.getPort());
|
||
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
|
||
out.writeObject(new Message(user.getName(), message));
|
||
}
|
||
catch(IOException e){}
|
||
}
|
||
System.out.println("Outdoor users:");
|
||
for(Socket s:outdoor_dest_sockets)
|
||
{
|
||
try
|
||
{
|
||
System.out.println(s.getInetAddress().getHostAddress() + ": local port " + s.getLocalPort() + ", remote port " + s.getPort());
|
||
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
|
||
out.writeObject(new Message(user.getName(), message));
|
||
}
|
||
catch(IOException e){}
|
||
}
|
||
}
|
||
|
||
void disconnect()
|
||
{
|
||
send(null);
|
||
try
|
||
{
|
||
Thread.sleep(1000);
|
||
}
|
||
catch(InterruptedException e) {}
|
||
|
||
for(Socket s:dest_sockets)
|
||
{
|
||
try
|
||
{
|
||
s.close();
|
||
}
|
||
catch(IOException e){}
|
||
}
|
||
}
|
||
}
|