I am writing a program with a threaded server. I have it set up so that mulitple clients can connect to the server and transmit a string that the server echoes back to the client that sent it. I am trying to get the server to transmit any string sent by a client to all clients and am lost as to how to do this. Any help would be appreciated.
Replay:Threads
how far have you gotten? do you have any code?
Replay:Threads
Here is the code for the threaded server.
package socket;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
class ClientWorker implements Runnable {
private Socket client;
private JTextArea textArea;
ClientWorker(Socket client, JTextArea textArea) {
this.client = client;
this.textArea = textArea;
}
public void run(){
String line;
BufferedReader in = null;
PrintWriter out = null;
try{
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.out.println("in or out failed");
System.exit(-1);
}
while(true){
try{
line = in.readLine();
//Send data back to client
out.println(line);
textArea.append(line);
} catch (IOException e) {
System.out.println("Read failed");
System.exit(-1);
}
}
}
}
class SocketThrdServer extends JFrame{
JLabel label = new JLabel("Text received over socket:");
JPanel panel;
JTextArea textArea = new JTextArea();
ServerSocket server = null;
SocketThrdServer(){ //Begin Constructor
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBackground(Color.white);
getContentPane().add(panel);
panel.add("North", label);
panel.add("Center", textArea);
} //End Constructor
public void listenSocket(){
try{
server = new ServerSocket(4444);
} catch (IOException e) {
System.out.println("Could not listen on port 4444");
System.exit(-1);
}
while(true){
ClientWorker w;
try{
w = new ClientWorker(server.accept(), textArea);
Thread t = new Thread(w);
t.start();
} catch (IOException e) {
System.out.println("Accept failed: 4444");
System.exit(-1);
}
}
}
protected void finalize(){
//Objects created in run method are finalized when
//program terminates and thread exits
try{
server.close();
} catch (IOException e) {
System.out.println("Could not close socket");
System.exit(-1);
}
}
public static void main(String[] args){
SocketThrdServer frame = new SocketThrdServer();
frame.setTitle("Server Program");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
frame.addWindowListener(l);
frame.pack();
frame.setVisible(true);
frame.listenSocket();
}
}
and here is the code for the client.
package socket;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
class SocketClient extends JFrame
implements ActionListener {
JLabel text, clicked;
JButton button;
JPanel panel;
JTextField textField;
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
SocketClient(){ //Begin Constructor
text = new JLabel("Text to send over socket:");
textField = new JTextField(20);
button = new JButton("Click Me");
button.addActionListener(this);
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBackground(Color.white);
getContentPane().add(panel);
panel.add("North", text);
panel.add("Center", textField);
panel.add("South", button);
} //End Constructor
public void actionPerformed(ActionEvent event){
Object source = event.getSource();
if(source == button){
//Send data over socket
String text = textField.getText();
out.println(text);
textField.setText(new String(""));
//Receive text from server
try{
String line = in.readLine();
System.out.println("Text received :" + line);
} catch (IOException e){
System.out.println("Read failed");
System.exit(1);
}
}
}
public void listenSocket(){
//Create socket connection
try{
socket = new Socket("localhost", 4444);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.out.println("Unknown host");
System.exit(1);
} catch (IOException e) {
System.out.println("No I/O");
System.exit(1);
}
}
public static void main(String[] args){
SocketClient frame = new SocketClient();
frame.setTitle("Client Program");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
frame.addWindowListener(l);
frame.pack();
frame.setVisible(true);
frame.listenSocket();
}
}
Replay:Threads
I'm taking a random guess that this is some kind of chat server, right?
Anyways, I would recommend placing all the Socket connections in an array, that way, you can keep control of the number of conections that you accept, etc..
And, thus, you can do something as simple as this to send a message via all sockets:
// The Sockets array is called 'sock'.
// You recieve a message, and assign it to the String variable 'str'.
// You now write that string to all clients:
for ( int i = 0; i < sock.length; i++ ) {
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(sock[i].getOutputStream()));
wr.write( str );
wr.flush();
} catch (IOException e) {
}
}
// etc.
Good luck,
[r.D]
Replay:Threads
Thanks for the help.
I am still running into trouble. I have spent all evening trying to get it to work. I originally set up an array of type Socket in the ClientWorker constructor, but that gave me trouble incrementing my array counter. It reset it each time a new thread was added. I then set it up in listenSocket of type ClientWorker and tried to pass this array to my ClientWorker class so that i could send the new message to all clients as they came in. This didn't throw any error messages, it just locked up the program. Any more help would be appreciated, I'll work on it more tommorow and post if i figure it out.
Replay:Threads
actually, you should have the transmission handled by the threads, really.. the general theory for this would be:
each client connected to the server, is represented by a Client class.. in this Client class is a publicly accessible String data storage container called the cubbyhole. when you wish to transmit a message to all clients, you traverse an array of the clientsputting the message into the cubbyhole. you can then also wake up each thread (if they are sleeping, which they probably will be/should be) and the thread will send the data, before going back to sleep
alternately, you CAN follow the advice given by philwx, but do note that one thread will be responsible for transmitting the message to all clients. this could cause clients near the end of the list to experience delays if there are errors to be handled as a result of messaging clients earlier in the list.
i noted that the data container be called a cubby hole for a good reason. Sun jave a java tutorial about managing multiple threaded communication, and it is called CubbyHole.java.. it introduces the concept of waiting and sleeping threads in a shared data environment..
Replay:Threads
and heres another tip.. multithreaded programming is hard, and weird.
it may help to like of a thread as a chef, and a class is like a recipe book, and the methods are recipes. you can create a new Chef (thread) at any time and tell him to start following a recipe.. he may, during the course of his execution, cross over into other recipe books that were the starting recipes of other chefs... its an analogy that really helps you separate a thread from a class.. if one thread has reached a certain point ina class and cant do anymore, it can go to sleep.. but another chef can come in, and follow the recipe right through, and go again without the first chef knowing.
if a chef makes a mess (exception) during the course of his work, then he must clean it up before he bails out of the kitchen (because run() cannot throw an exception)