I'm creating a chat for a game that runs on a server and client system, and then of course the game on the server client system, but I cannot get my multithreaded program to work, and I'll explain how below. What I can say is the server client system works when single threaded.
To start, my connection class:
public class Connection {
private Server server;
private Client client;
private boolean serverChosen;
public Connection(){
server = new Server();
this.serverChosen = true;
}
public Connection(String IP){
client = new Client(IP);
this.serverChosen = false;
}
public synchronized void sendObjects(Object obj) throws IOException{
if(serverChosen){
server.sendObjects(obj);
}else{
client.sendObjects(obj);
}
}
public synchronized Object receiveObjects() throws ClassNotFoundException, IOException{
if(serverChosen){
return server.receiveObjects();
}else{
return client.receiveObjects();
}
}
public Object waitForObject() throws ClassNotFoundException, IOException{
int i = 0;
Object obj;
while(true){
obj = receiveObjects();
i++;
if(obj != null || i >= 100){
return obj;
}
}
}
}
Server and Client classes:
public class Server implements Serializable{
private ObjectOutputStream output;
private ObjectInputStream input;
private ServerSocket server;
private Socket connection;
//constructor
public Server(){
try{
server = new ServerSocket(8790, 10); //8798 is a dummy port for testing, this can be changed. The 100 is the maximum people waiting to connect.
try{
//Trying to connect and have conversation
waitForConnection();
setupStreams();
}catch(EOFException eofException){
}
} catch (IOException ioException){
ioException.printStackTrace();
}
}
//wait for connection, then display connection information
private void waitForConnection() throws IOException{
connection = server.accept();
}
//get stream to send and receive data
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
}
public ObjectOutputStream getOutput(){
return output;
}
public ObjectInputStream getInput(){
return input;
}
public void sendObjects(Object obj) throws IOException{
output.writeObject(obj);
output.flush();
}
public Object receiveObjects() throws IOException, ClassNotFoundException{
return input.readObject();
}
}
public class Client extends JFrame implements Serializable{
private static final long serialVersionUID = 1L;
private ObjectOutputStream output;
private ObjectInputStream input;
private String serverIP;
private Socket connection;
private boolean next = true;
//constructor
public Client(String host){
serverIP = host;
try{
connectToServer();
setupStreams();
}catch(EOFException eofException){
}catch(IOException ioException){
ioException.printStackTrace();
}
}
public Client(){
serverIP = "127.0.0.1";
try{
connectToServer();
if(next){
setupStreams();
}
}catch(EOFException eofException){
//t.append("Connection was terminated");
}catch(IOException ioException){
ioException.printStackTrace();
}
}
//connect to server
private void connectToServer(){
int i = 0;
do {
try {
connection = new Socket(InetAddress.getByName(serverIP), 8790);
next = true;
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Server was not found, The program will try again in 1 second; number of tries left: " + (10-i));
next = false;
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
i++;
}
}while(!next && i<=10);
if(!next){
JOptionPane.showMessageDialog(null, "Unable to connect to the server. Make sure the I.P. adress is correct, the ports are not blocked, or a firewall has not prevented connections.... IDK man... it's just me and all of this code... maybe the server isn't even running??");
}
}
//set up streams
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
}
public ObjectOutputStream getOutput(){
return output;
}
public ObjectInputStream getInput(){
return input;
}
public void sendObjects(Object obj) throws IOException{
output.writeObject(obj);
output.flush();
}
public Object receiveObjects() throws ClassNotFoundException, IOException{
return input.readObject();
}
}
The class I'm running everything on is the Frame class:
public class Frame implements ActionListener{
private int width;
private int height;
private JFrame jframe;
private Board board;
private JTextArea textBox;
private JScrollPane pane;
private Connection connection;
private JTextArea userText;
private JScrollPane userPane;
private JButton send;
private NetworkReceiver net;
public Frame(int width, int height, Connection connection, Board player, Board opponent){
this.width = width;
this.height = height;
this.connection = connection;
board = new Board(player, opponent);
init();
textBox = new JTextArea("CHAT WINDOW");
textBox.setWrapStyleWord(true);
textBox.setLineWrap(true);
textBox.setBackground(Color.GRAY);
textBox.setBounds(height, 0, width - (height) - 20, height-40);
textBox.setEditable(false);
userText = new JTextArea("Enter Messages Here");
userText.setWrapStyleWord(true);
userText.setLineWrap(true);
userText.setBackground(Color.WHITE);
userText.setBounds(height, height-40, width - (height) - 20, 40);
pane = new JScrollPane(textBox,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
pane.setBounds(height, 0, width - (height), height-40);
userPane = new JScrollPane(userText,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
userPane.setBounds(height, height-40, width - (height) - 20, 40);
send = new JButton();
send.setIcon(Utility.getImageIcon(Utility.getBufferedImage(Assets.send)));
send.setBounds(width - 20, height - 40, 20, 40);
send.addActionListener(this);
send.setBackground(Color.WHITE);
jframe = new JFrame();
jframe.setBackground(Color.DARK_GRAY);
jframe.getContentPane().setPreferredSize(new Dimension(width, height));
jframe.setLayout(null);
jframe.pack();
jframe.setLocationRelativeTo(null);
jframe.add(pane);
jframe.add(userPane);
jframe.add(send);
for(Space[] s: board.getSpaces()){
for(Space space: s){
jframe.add(space);
}
}
for(Space[] s: board.getSpaces()){
for(Space space: s){
space.addActionListener(this);
}
}
for(Space[] s: board.getSpaces()){
for(Space space: s){
if(space.getTile() != null){
space.setBackground(space.getTile().getColor());
}
}
}
for(Space[] s: board.getSpaces()){
for(Space space: s){
if(space.getPiece() != null){
space.setIcon(Utility.getImageIcon(space.getPiece().getImage()));
}
}
}
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setVisible(true);
net = new NetworkReceiver(connection, this);
net.start();
}
private void init(){
//stuff
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == send){
send();
}
}
private synchronized void send() {
String message = "YOU- " + userText.getText();
userText.setText("");
String totalMessage = textBox.getText();
textBox.setText(totalMessage + "\n" + message);
new NetworkSender(connection, message).start();
}
public synchronized void showMessage(String s){
String totalMessage = "Opponent- " + textBox.getText();
textBox.setText(totalMessage + "\n" + s);
}
I do not want to delete anything more in the constructor above in case it is in some way causing the issue(which I doubt but since I cannot find the issue better safe than sorry)
Here is the NetworkSender and NetworkReceiver classes:
public class NetworkSender extends Thread{
private Connection c;
private String msg;
public NetworkSender(Connection c, String msg){
this.c = c;
this.msg = msg;
}
public void run(){
try {
System.out.println("Trying to send");
c.sendObjects(msg);
System.out.println("Sent");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class NetworkReceiver extends Thread{
private Connection c;
private boolean running = true;
private Frame f;
public NetworkReceiver(Connection c, Frame f){
this.c = c;
this.f = f;
}
public void run(){
while(running){
System.out.println("running");
Object obj = null;
try {
obj = c.receiveObjects();
System.out.println("received");
} catch (ClassNotFoundException e) {
System.out.println("failed - class exception");
e.printStackTrace();
} catch (IOException e) {
System.out.println("failed - IO exception");
e.printStackTrace();
running = false;
}
if(obj != null){
if(obj instanceof String){
f.showMessage((String)obj);
}
}
}
}
public void kill(){
running = false;
}
}
The exact spot of breaking is in the NetworkSender class. In the console, I receive "Trying to send" but never "sent." This leads me to think that I'm setting up the threads wrong, the threads are somehow unable to talk to each other (sender and receiver threads), or the server/client system is done improperly for multi-threading.
I have looked up this issue extensively, but I could not find a solution anywhere that worked, so I apologize if there is a solution I over looked. If everything is checking out, I can post my connection, server, and client classes if needed, but I'm assuming they are functional since they work on the EDT. As I put nearly 4 hours scouring online, I ask that if you think this is a duplicate question you comment a link first, as I am almost sure I have seen it already lol.
The immediate reason is that you synchronize both receiving and sending on the Connection object itself. Meaning while one thread is inside receiveObjects(), no other thread can enter either send or receiveObjects(). Thus your receiving thread permanently blocks you from sending.
You could potentially make it work by removing synchronized from the methods on your connection class and instead making the respective methods on your client and server synchronize on selected different objects, for example the respective Input/Output-Streams.
Still, its a design desaster (not mincing words here). Your best course of action is probably to rethink the design - your choice of abstractions (or rather the lack of) and the choices you made with regards to assignment of responsibilities leave room for improvement.
Related
I'm making code for a Server that has multiple clients that joins in it. Here's what the server's looks like.
public class Server {
private final ServerSocket serverSocket;
private static final int PORT = 9000;
private WaitingRoom wroom = new WaitingRoom();
public Server(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
public void startServer() throws InterruptedException,Exception{
try {
int count = 0;
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
System.out.println("A new client has connected!");
ClientHandler clientHandler = new ClientHandler(new Player(count),socket);
Thread thread = new Thread(clientHandler);
thread.start();
count++;
System.out.println(clientHandler.getPlayer().getNickname());
wroom.join(clientHandler.getPlayer());
}
} catch (IOException e) {
closeServerSocket();
}
}
public void closeServerSocket() {
try {
if(serverSocket != null)
serverSocket.close();
}catch (IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException,InterruptedException,Exception{
ServerSocket serverSocket = new ServerSocket(PORT);
Server server = new Server(serverSocket);
server.startServer();
}
}
I've a class named ClientHandler that manages these clients in a thread for each, and i pass it also in the Player class because i will use it for things like: Send msg, Receive msg. That's the ClientHandler class:
public class ClientHandler implements Runnable {
public static ArrayList<ClientHandler> clientHandlers = new ArrayList<>();
private Player player;
private String nickname;
private Socket socket;
private BufferedReader bufferedReader;
private BufferedWriter bufferedWriter;
public ClientHandler(Player player,Socket socket) throws InterruptedException,Exception{
try {
this.socket = socket;
this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.bufferedWriter= new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
nickname = this.bufferedReader.readLine();
player.init(nickname, this);
clientHandlers.add(this);
broadcastMessage("SERVER: " + nickname + " è entrato");
} catch (IOException e) {
closeEverything(socket, bufferedReader, bufferedWriter);
}
}
public Player getPlayer(){
return player;
}
public BufferedWriter getBufferedWriter(){
return bufferedWriter;
}
public BufferedReader getBufferedReader(){
return bufferedReader;
}
#Override
public void run() {
String messageFromClient;
while (socket.isConnected()) {
/* try {
// messageFromClient = bufferedReader.readLine();
} catch (IOException e) {
closeEverything(socket, bufferedReader, bufferedWriter);
break;
} */
}
}
public void broadcastMessage(String messageToSend) {
for (ClientHandler clientHandler : clientHandlers) {
try {
if (!clientHandler.nickname.equals(nickname)) {
clientHandler.bufferedWriter.write(messageToSend);
clientHandler.bufferedWriter.newLine();
clientHandler.bufferedWriter.flush();
}
} catch (IOException e) {
closeEverything(socket, bufferedReader, bufferedWriter);
}
}
}
private void writeToClient(String text) throws IOException{
bufferedWriter.write(text);
bufferedWriter.newLine();
bufferedWriter.flush();
}
public void removeClientHandler() {
clientHandlers.remove(this);
broadcastMessage("SERVER: " + nickname + " è uscito");
}
public void closeEverything(Socket socket, BufferedReader bufferedReader, BufferedWriter bufferedWriter) {
removeClientHandler();
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (bufferedWriter != null) {
bufferedWriter.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Now, the problem is: if I want to create a class named "WaitingRoom" for let players to waint until the wait's done. Where and how could I instantiate it? Before the linked code, i was instantiating it in the ClientHandler, but it worked only for a client a time. Here's what i wrote for the WaitingRoom class:
public class WaitingRoom {
private final int MAXPLAYERS = 2;
private ArrayList<Player> players = new ArrayList<Player>();
public ArrayList<Player> getPlayers(){
return players;
}
public void join(Player player) throws IOException,InterruptedException,Exception{
while(!addPlayer(player)){
player.sendMsg("waiting for join");
TimeUnit.SECONDS.sleep(1);
}
waitStart(player);
}
public boolean addPlayer(Player player){
if (players.size() >= MAXPLAYERS) return false;
players.add(player);
return true;
}
public boolean removePlayer(int idPlayer){
for(Player player : players){
if(player.getId() == idPlayer){
players.remove(player);
return true;
}
}
return false;
}
public void waitStart(Player player) throws IOException,InterruptedException,Exception{
if(players.size() < MAXPLAYERS)
player.sendMsg("sei entrato nella stanza d'attesa");
while(players.size() < MAXPLAYERS){
player.sendMsg("(" + players.size() + "/2) in attesa di giocatori...");
TimeUnit.SECONDS.sleep(1);
}
player.sendMsg("Inizio Gioco");
Player[] players2 = new Player[MAXPLAYERS];
for(int i=0;i<MAXPLAYERS;i++){
players2[0] = new Player(players.get(i).getId()).init(players.get(i).getNickname(),players.get(i).getClientHandler());
}
new Gioco(players2);
cleanRoom();
}
public void cleanRoom(){
players.clear();
}}
it's a really basic concept for waiting room and I only need a place where user must to wait before a gameloop. For example i don't really need multiple wainting rooms, one is ok for me, maybe.
I want to send an object having OS Name to a server. This OS Name output should be of PC sending object but it displays OS Name of PC running server..
Here is my code :
//Client : it can send data i.e. object to server
class Client
{
private Socket socket = null;
private ObjectOutputStream outputStream = null;
public Client(String con){
System.out.println("conn value: "+con);
java.util.Timer t = new java.util.Timer();
try{
socket = new Socket(con, 27051);
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
outputStream = new ObjectOutputStream(socket.getOutputStream());
SI sysinfo=new SI();
outputStream.writeObject(sysinfo);
System.out.println("Sent Data: "+sysinfo.otherInfo());
} catch (Exception se) {
t.cancel();
}
}
}, 0, 1);
}
catch(Exception em)
{
}
}
}
//Server class: should receive data from client
class Server extends SwingWorker<Void,Void>{
Socket csocket=null;
protected Void doInBackground() throws Exception {
final ServerSocket ssock = new ServerSocket(27051);
System.out.println("Server Listening..!!");
while (true) {
try{
Socket sock = ssock.accept();
new Thread(new Server(sock)).start();
}
catch(Exception e){
System.out.println("unabke to create socket");
}
}
}
Server() throws Exception{
doInBackground();
}
Server(Socket csocket) {
this.csocket=csocket;
Thread t1=new Thread(r1);
t1.start();
}
Runnable r1=new Runnable()
{
public void run() {
try {
System.out.println("Run initated");
while(true)
{
if(csocket.isClosed())
{
break;
}
else{
System.out.println(csocket);
ObjectInputStream inStream = new
ObjectInputStream(csocket.getInputStream());
SI sysinfo= (SI) inStream.readObject();
System.out.println("Received: "+sysinfo.otherInfo());
System.out.println(ObjectStreamClass.lookup(sysinfo.getClass()).getSerialVersion
UID());
}
}
}
catch (Exception e) {
System.out.println("Exception"+ e.getMessage());
}
}
};
}
//class undergoing serialization
public class SI implements Serializable
{
private static final long serialVersionUID = 1L;
String otherInfo()
{
OperatingSystemMXBean bean = (com.sun.management.OperatingSystemMXBean) ManagementFactory
.getOperatingSystemMXBean();
String os_name=bean.getName();
return os_name;
}
}
//class A: It has main function and it executes first and user decides whether he/she want to be in server mode or in client mode. As user cannot be in 2 modes simultaneously..
class A
{
public static void main(String[] args) throws Exception
{
System.out.println("Enter 0 for Server 1 for Client Mode");
Scanner s=new Scanner(System.in);
int i=s.nextInt();
if(i==0)
{
Server ser=new Server();
ser.execute();
}
else if(i==1)
{
System.out.println("Enter IP");
String conn=s.next();
Client c=new Client(conn);
}
else
System.out.println("Invalid Selection exit..");
}
}
As I wrote in my comment you must transfer the data, not the function. Some sample code below...
First, change your SI class as follows:
public class SI implements Serializable {
private static final long serialVersionUID = 1L;
private String osName;
public void setOsName(String osName) { this.osName = osName; }
public void getOsName() { return this.osName; }
}
Second, modify your client to first determine the OS and the build the SI object...
...
OperatingSystemMXBean bean = (com.sun.management.OperatingSystemMXBean) ManagementFactory
.getOperatingSystemMXBean();
String osName=bean.getName();
SI sysinfo = new SI();
sysinfo.setOsName(osName);
...
outputStream.writeObject(sysinfo);
...
Third, modify your server accordingly.
I'm creating a token ring with sensors where every sensor is a process apart. When i start a sensor it communicates with the gateway and gets the list of the actual sensors already on the system .
The problem is that every time i start a new process i want every already existing sensor to get the updated list, so to understand that other sensors have been added and the list is no longer the one they had but a new updated one.(So lets say the processes must always have the same list). I use a server which i call serverSocket which listens for messages. I can make it possible for the server to understand that the list has been changed but what i cant do is how to change the value of the sensorList found on my SensorClient class, to be updated? In the code bellow i show what i'm doing but the sensorList keeps being the old one,not being updated :/ Can anyone please help me? Thank you :)
SensorClient where i start a new process sensor
public class SensorClient {
public static void main(String[] args) throws Exception {
Sensor sensor = new Sensor(type,identificator,portnumber,ipnumber,gatewayAddr,timestamp);
Gson gson = new Gson();
String message = gson.toJson(sensor);
Client c = Client.create();
WebResource r = c.resource("http://localhost:9999/gateway/");
ClientResponse response = r.path("sensors/add").type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).post(ClientResponse.class, message);
if (response.getStatus() == 200) {
repeat = false;
Type collectionType = new TypeToken<ArrayList<Sensor>>(){}.getType();
ArrayList<Sensor> sensorList = gson.fromJson(response.getEntity(String.class), collectionType);
System.out.println("Starting the sensor ...");
System.out.println("Push exit when you want to delete the sensor!");
int position = 0;
for(int i = 0; i< sensorList.size();i++){ if(sensorList.get(i).getIdentificator().equalsIgnoreCase(sensor.getIdentificator()) ) position = i;
}
sensors.Sensor.simulation(type, identificator);// special thread for sensors simulations
createSensor.getInstance().setPrevNextWhenAdd(position,sensorList);
serverSocket serverSocket = new serverSocket(portnumber,sensorList,position,sensorList.get(position).getNext());
serverSocket.start();
StopSensor stopSensor = new StopSensor(identificator,portnumber,position,sensorList);
stopSensor.start();
oneSensor s = new oneSensor(portnumber,sensorList);
s.start();
} else {
repeat = true;
count +=1;
System.out.println("Error. Wrong data! ");
}
}
while (repeat );
}
}
}
The serverSocket thread
public class serverSocket extends Thread {
public int port,nextPort;
ArrayList<gateway.Sensor> sensorList;
public static int position;
public serverSocket(int port, ArrayList<gateway.Sensor> sensorList,int position,int nextPort) {
this.port = port;
this.nextPort=nextPort;
this.sensorList= sensorList;
this.position=position;}
public void run() {
ServerSocket welcomeSocket;
Socket connectionSocket;
try {
welcomeSocket = new ServerSocket(port);
while (true) {
connectionSocket = welcomeSocket.accept();
receivedMessages thread = new receivedMessages(connectionSocket,sensorList,position,nextPort);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
System.err.println("Error!!!!!!!!!");
}
}
}
The receivedMessages thread
public class receivedMessages extends Thread {
private BufferedReader inFromClient;
private Socket connectionSocket;
ArrayList<gateway.Sensor> sensorList;
int position,nextPort;
public receivedMessages(Socket socket, ArrayList<gateway.Sensor> sensorList,int position,int nextPort){
connectionSocket = socket;
this.sensorList=sensorList;
this.position=position;
this.nextPort=nextPort;
try {
inFromClient = new BufferedReader( new InputStreamReader(connectionSocket.getInputStream()));
} catch (IOException e) { e.printStackTrace(); }
}
#Override
public void run() {
try {
String message = (inFromClient.readLine().toString());
if (message.startsWith("Next") || message.startsWith("Previous")) {
System.out.println(message);
} else if (message.startsWith("The")) {
System.out.println(message); createSensor.getInstance().setPrevNextWhenDelete(position, sensorList);
} else {// i receive the message that the list has changed
System.out.println(message);
sensorList = createSensor.getInstance().getSensorList();
System.out.println("Updated " + sensorList);}
This class has methods used by gateway to register a sensor when it makes the request
public class createSensor {
private static createSensor instance = null;
private ArrayList<Sensor> sensor = new ArrayList<>();
public int position, prevPosition, nextPosition, prevPort, nextPort;
private createSensor() { }
public static synchronized createSensor getInstance() {
if (instance == null) {
instance = new createSensor();
}
return instance;
}
public synchronized ArrayList insertSensor(String type, String identificator, int port, String id, String gatwayAddr, long timestamp) throws IOException {
sensor.add(new Sensor(type, identificator, port, id, gatwayAddr, timestamp));
return new ArrayList<>(sensor); //
}
}
public synchronized boolean hasMeasurements() {
while (InnerBuffer.getInstance().emptyInnerBuffer())
return false;
return true;
}
public synchronized void setPrevNextWhenDelete(int position,ArrayList<Sensor> sensorList) throws IOException {
//code
}
public synchronized ArrayList<Sensor> getSensorList() {
return new ArrayList<>(sensor);
}
public synchronized int size() {
return sensor.size();
}
public synchronized String returnRecentMeasurement (String id){
String recentMeasurement=null;
for (Sensor sensori : sensor) {
if (sensori.getIdentificator().equalsIgnoreCase(id))
recentMeasurement= InnerBuffer.getInstance().returnRecentMeasurements(id);
else
recentMeasurement = null;}
return recentMeasurement;
}
public synchronized void setPrevNextWhenAdd() throws IOException { //some other code where int position, prevPosition, nextPosition, prevPort, nextPort get their values. }}
I have a big problem with an exercise from my java teacher.
In theory the exercise must have the following points:
-Sockets
-Clients
-Server
-The server uses MySql for something
-Login
-Md5 to save the passwords
-Secure socket
With this I decide to make a chat in theory should be easy stuff but... I'm completely lose.
More or less I made the basic (Secure Socket, server, clients) but even that doesn't work, but the IDE makes no fail in theory should be fine.
Someone May help me?
The code is just below:
ChatClient this make work the client, loading the interface and the features:
public class ChatClient
{
private Socket s;
private ClientPanel panel;
public static void main(String[] args)
{
new ChatClient();
}
public ChatClient()
{
try
{
Window();
s = new Socket("localhost" , 5557);
ClientControl control = new ClientControl(s, panel);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void Window()
{
JFrame v = new JFrame();
panel = new PanelCliente(v.getContentPane());
v.pack();
v.setVisible(true);
v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
ServerChat this create a server chat with secure sockets as one of the requisites of the exercise:
public class ServerChat extends Thread
{
public static void main(String[] args)
{
int port= 5090;
SSLServerSocketFactory sslserver = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
try
{
SSLServerSocket sslsocket = (SSLServerSocket)sslserver.createServerSocket();
InetSocketAddress socketAddress = new InetSocketAddress("localhost" , port);
while(true)
{
SSLSocket socket = (SSLSocket)sslsocket.accept();
System.out.println("Client: " + socket.getInetAddress().getHostName() + " Conected");
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
public class ClientControl implements ActionListener, Runnable
{
private DataInputStream dataInput;
private DataOutputStream dataOutput;
private ClientPanel panel;
public ClientControl (Socket s, ClientPanel panel)
{
this.panel = panel;
try
{
dataInput = new DataInputStream(s.getInputStream());
dataOutput = new DataOutputStream(s.getOutputStream());
panel.addActionListener(this);
Thread t = new Thread(this);
t.start();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void actionPerformed (ActionEvent event)
{
try
{
dataOutput.writeUTF(panel.getTexto());
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void run()
{
try
{
String text = dataInput.readUTF();
panel.addTexto(text);
panel.addTexto("\n");
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Client Thread in theory this make posible to run the client as a thread and implements it's functions:
public class ClientThread implements Runnable, ListDataListener
{
private DefaultListModel conversation;
private Socket s;
private DataInputStream dataInput;
private DataOutputStream dataOutput;
public ClientThread (DefaultListModel conversation, Socket s)
{
this.conversation = conversation;
this.s = s;
try
{
dataInput = new DataInputStream(s.getInputStream());
dataOutput = new DataOutputStream(s.getOutputStream());
conversation.addListDataListener(this);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void run()
{
try
{
while (true)
{
String text = dataInput.readUTF();
System.out.println(text);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void intervalAdded(ListDataEvent e)
{
String text = (String) conversation.getElementAt(e.getIndex0());
try
{
dataOutput.writeUTF(text);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
#Override
public void contentsChanged(ListDataEvent arg0)
{
}
#Override
public void intervalRemoved(ListDataEvent arg0)
{
}
}
Client Panel is below basically makes a simple design with JSwing to create and interface where you see the conversation and you can writte whatever you want:
public class ClientPanel
{
private JScrollPane scroll;
private JTextArea textArea;
private JTextField textField;
private JButton button;
public ClientPanel(Container cont)
{
cont.setLayout(new BorderLayout());
textArea = new JTextArea();
scroll = new JScrollPane(textArea);
JPanel panel = new JPanel(new FlowLayout());
textField = new JTextField(50);
button = new JButton("Send");
panel.add(textField);
panel.add(button);
cont.add(scroll, BorderLayout.CENTER);
cont.add(panel, BorderLayout.SOUTH);
}
public void addActionListener (ActionListener action)
{
textField.addActionListener(action);
button.addActionListener(action);
}
public void addTexto (String text)
{
textArea.append(text);
}
public String getTexto()
{
String text = textField.getText();
textField.setText(text);
return text;
}
}
How can I add a database to Log in users?
How can I add there Md5 to protect the passwords?
How can I make this all work together?
That's my questions
You have a server and clients and want to write a chat. So the server is the center and holds the connection to the database where all persistent data is stored. The password is not stored as plain text, only it's md5 hash is stored in database.
Furthermore, only the server holds a connection to the database.
This answers where to use MD5 and which guy the master of the database is.
You have already created a SeverChat. That guy is responsible to listen for new clients to connect. If a new client wants to connect, the ServerChat has to spawn a new ClientController.
Your ClientControl does not look like what I mean. A ClientControll is responsible to take the request from the specific client he is connect to, handle the request and send an answer to the client.
That means you need some sort of a protokol. You can use ObjectStreams to send objects from the client to the sever and vice versa.
This makes it easier to define a protokol.
To get an idea of the ClientController:
class ClientController extends Thread {
private final ObjectInputStream dataInput;
private final ObjectOutputStream dataOutput;
private boolean loggedIn = false;
ClientController(ObjectInputStream dataInput, ObjectOutputStream dataOutput) {
this.dataInput = dataInput;
this.dataOutput = dataOutput;
}
#Override
public void run() {
try {
boolean stayConnected = true;
while (stayConnected) {
Object data = dataInput.readObject();
if (data instanceof LoginAction) {
// check data an do login
this.loggedIn = true;
dataOutput.write(new LoginResponse(/* response data */));
}
if (data instanceof RequestChatDataAction) {
if (this.loggedIn) {
dataOutput.write(new NotLoggedInResponse());
} else {
dataOutput.write(new ChatDataResponse(/* chat data.. */));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
The LoginAction, LoginResponse a.s.o. objects define your protokol. You need of cause more objects to implement all features and these objects have to implement java.io.Serializable. Otherwise, you will not be able to send them over the wire.
You have to write counter part as well - the client.
The client starts up, connects to the server and tries to login. If login is successfull, the client waits for new chat data and displays it.
If the user types in something, this data is send to the server and will be added to the 'gobal' chat data.
I would recommend not to add the gui elements before the client-server communication is done. You can use the System.out and System.in to interact with the user.
So, I hope that helps you.
Furthermore, SO is not for questions like: Do my homework. I see that you already have taken the tour.
Reading How to create a Minimal, Complete, and Verifiable example would be appreciated.
I'm building simple socket server-client application consisting of:
Server project (which creates new client handler thread when socket is accepted) and a Client project (which establishing connection with the server and displaying gui with message thread open).
So far I'm able to connect using multiple clients and chat with no problems.
I've set a command called !getusers that should display all connected users to the requesting client.
When I do so, I'm suddenly unable to continue and chat, the client simply get stuck, I do get the connected users list though.
As for a request here is the entire client code:
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static java.lang.System.out;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ChatClient extends JFrame implements ActionListener {
String uname;
PrintWriter pw;
BufferedReader br;
JTextArea taMessages, taUserList;
JTextField tfInput;
JButton btnSend, btnExit;
Socket client;
public ChatClient(String uname, String servername) throws Exception {
super("Connected as: " + uname); // set title for frame
this.uname = uname;
client = new Socket(servername, 18524);
br = new BufferedReader(new InputStreamReader(client.getInputStream()));
pw = new PrintWriter(client.getOutputStream(), true);
pw.println(uname); // send name to server
//bring up the chat interface
buildInterface();
new MessagesThread().start(); // create thread that listens for messages
}
public void buildInterface() {
btnSend = new JButton("Send");
btnExit = new JButton("Exit");
//chat area
taMessages = new JTextArea();
taMessages.setRows(10);
taMessages.setColumns(50);
taMessages.setEditable(false);
//online users list
taUserList = new JTextArea();
taUserList.setRows(10);
taUserList.setColumns(10);
taUserList.setEditable(false);
//top panel (chat area and online users list
JScrollPane chatPanel = new JScrollPane(taMessages, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JScrollPane onlineUsersPanel = new JScrollPane(taUserList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JPanel tp = new JPanel(new FlowLayout());
tp.add(chatPanel);
tp.add(onlineUsersPanel);
add(tp, "Center");
//user input field
tfInput = new JTextField(50);
//buttom panel (input field, send and exit)
JPanel bp = new JPanel(new FlowLayout());
bp.add(tfInput);
bp.add(btnSend);
bp.add(btnExit);
add(bp, "South");
btnSend.addActionListener(this);
tfInput.addActionListener(this);//allow user to press Enter key in order to send message
btnExit.addActionListener(this);
setSize(500, 300);
setVisible(true);
pack();
}
#Override
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == btnExit) {
pw.println("!end"); // send end to server so that server know about the termination
System.exit(0);
} else if(tfInput.getText().contains("!getusers")){
pw.println("!getusers");
}else{
// send message to server
pw.println(tfInput.getText());
}
}
public static void main(String args[]) {
// take username from user
String name = JOptionPane.showInputDialog(null, "Enter your name: ", "Username",
JOptionPane.PLAIN_MESSAGE);
String servername = "localhost";
try {
new ChatClient(name, servername);
} catch (Exception ex) {
out.println("Unable to connect to server.\nError: " + ex.getMessage());
}
} // end of main
// inner class for Messages Thread
class MessagesThread extends Thread {
#Override
public void run() {
String line;
try {
while (true) {
line = br.readLine();
taMessages.append(line + "\n");
taMessages.setCaretPosition(taMessages.getDocument().getLength());//auto scroll to last message
} // end of while
} catch (Exception ex) {
}
}
}
} // end of client
Which then accepted and handled by the server, following is the entire server code:
public class ChatServer {
Vector<String> users = new Vector<String>();
Vector<HandleClient> clients = new Vector<HandleClient>();
public void process() throws Exception {
ServerSocket server = new ServerSocket(18524);
out.println("Server Started...");
while (true) {
Socket client = server.accept();
//add incoming client to connected clients vector.
HandleClient c = new HandleClient(client);
clients.add(c);
} // end of while
}
public static void main(String... args) throws Exception {
new ChatServer().process();
} // end of main
public void broadcast(String user, String message) {
// send message to all connected users
for (HandleClient c : clients) {
c.sendMessage(user, message);
}
}
/*
* Inner class, responsible of handling incoming clients.
* Each connected client will set as it's own thread.
*/
class HandleClient extends Thread {
String name = "";//client name/username
BufferedReader input;//get input from client
PrintWriter output;//send output to client
public HandleClient(Socket client) throws Exception {
// get input and output streams
input = new BufferedReader(new InputStreamReader(client.getInputStream()));
output = new PrintWriter(client.getOutputStream(), true);
// read name
name = input.readLine();
users.add(name); // add to users vector
broadcast(name, " Has connected!");
start();
}
public void sendMessage(String uname, String msg) {
output.println(uname + ": " + msg);
}
public void getOnlineUsers() {
for (HandleClient c : clients) {
for (int i = 0; i < users.size(); i++) {
broadcast("", users.get(i));
}
}
}
public String getUserName() {
return name;
}
public void run() {
String line;
try {
while (true) {
line = input.readLine();
if (line.equals("!end")) {
//notify all for user disconnection
broadcast(name, " Has disconnected!");
clients.remove(this);
users.remove(name);
break;
} else if(line.equals("!getusers")){
getOnlineUsers();
break;
}
broadcast(name, line); // method of outer class - send messages to all
} // end of while
} // try
catch (Exception ex) {
System.out.println(ex.getMessage());
}
} // end of run()
} // end of inner class
} // end of Server
Should I defince a new PrintWriter object for handling the onlineUsers request?
I'm sure I'm missing something here, but yet to figure out what exactly.
Ah, I have solved the puzzle.
public void run() {
String line;
try {
while (true) {
line = input.readLine();
if (line.equals("!end")) {
// Blah
} else if(line.equals("!getusers")){
getOnlineUsers();
break; << This breaks your read loop
}
broadcast(name, line); // method of outer class - send messages to all
} // end of while
} // try
catch (Exception ex) {
System.out.println(ex.getMessage());
}
} // end of run()
The break statement in your run() loop terminates your reading loop, so the server is no longer "listening" to your client. I believe if you remove the break, it should be all good.