So I'm working on a chat program and now I want to add a send file option.
I tried adding it and it worked but right after the file transfer finishes, both of the sockets close(the sockets of the two clients).
Here is an SSCCE for the Chat client:
public class SSCCEChatClient extends JFrame {
private JPanel contentPane;
private JTextField inputUsernameField;
private JTextArea textArea;
String serversock = "84.252.37.82";
String username;
Socket sock;
BufferedReader reader;
PrintWriter writer;
InputStreamReader streamreader;
public class IncomingReader implements Runnable{
public void run() {
String stream;
String[] data;
try {
while ((stream = reader.readLine()) != null) {
data = stream.split("`");
if(data[2].equals("receiveFile")&&(!data[3].equals(username))){
DataInputStream in = new DataInputStream(sock.getInputStream());
byte[] bytes = new byte[Integer.parseInt(data[1])];
in.read(bytes);
FileOutputStream fos = new FileOutputStream(System.getProperty("user.home") + "\\Desktop\\" + data[0]);
fos.write(bytes);
fos.close();
in.close();
textArea.append("Success!");
}else if(data[2].equals("server")){
textArea.append(data[0]);
}
}
}catch(Exception ex) {
}
}
}//Incoming Reader
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SSCCEChatClient frame = new SSCCEChatClient();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SSCCEChatClient() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
textArea = new JTextArea();
contentPane.add(textArea, BorderLayout.SOUTH);
JButton btnNewButton = new JButton("Send File");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File transferFile = new File (System.getProperty("user.home") + "\\Desktop\\PNG\\Night.png");
byte [] bytearray = new byte [(int)transferFile.length()];
try {
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(transferFile));
bin.read(bytearray,0,bytearray.length);
DataOutputStream os = new DataOutputStream(sock.getOutputStream());
writer.println(transferFile.getName() + "`" + transferFile.length() + "`receiveFile`" + username);
writer.flush();
os.write(bytearray,0,bytearray.length);
os.flush();
bin.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("File transfer complete");
}
});
contentPane.add(btnNewButton, BorderLayout.CENTER);
JButton btnNewButton_1 = new JButton("Connect");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
username = inputUsernameField.getText();
sock = new Socket(serversock, 5000);
streamreader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(streamreader);
writer = new PrintWriter(sock.getOutputStream());
Thread IncomingReader = new Thread(new IncomingReader());
IncomingReader.start();
writer.println(username + "``connect");
writer.flush();
} catch (Exception ex) {
textArea.append("\nCannot Connect!");
}
}
});
contentPane.add(btnNewButton_1, BorderLayout.WEST);
inputUsernameField = new JTextField();
contentPane.add(inputUsernameField, BorderLayout.NORTH);
inputUsernameField.setColumns(10);
}
}
and here is the Server side:
public class SSCCEServer {
static ArrayList<PrintWriter> clientOutputStreams;
static ArrayList<DataOutputStream> clientDataOutputStreams;
static ArrayList<String> onlineUsers = new ArrayList<>();
public class ClientHandler implements Runnable {
BufferedReader reader;
Socket sock;
PrintWriter client;
public ClientHandler(Socket clientSocket, PrintWriter user) {
// new inputStreamReader and then add it to a BufferedReader
client = user;
try {
sock = clientSocket;
System.out.println(clientSocket.getRemoteSocketAddress().toString() + " - ");
InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(isReader);
}
catch (Exception ex) {
System.out.println("error beginning StreamReader");
}
}
public void run() {
String message;
String[] data;
try {
while ((message = reader.readLine()) != null) {
data = message.split("`");
if(data[2].equals("receiveFile")){
DataInputStream in = new DataInputStream(sock.getInputStream());
byte[] bytes = new byte[Integer.parseInt(data[1])];
in.read(bytes);
tellEveryone(data[0] + "`" + data[1] + "`" + data[2] + "`" + data[3]);
for(DataOutputStream dos:clientDataOutputStreams){
try {
dos.write(bytes);
dos.close();
}
catch (Exception ex) {
System.out.println("error telling everyone");
}
}
tellEveryone("File transfer complete``server");
}else if(data[2].equals("connect")){
System.out.println(data[0] + "has connected.");
}else {
System.out.println("No Conditions were met.");
}
}
}
catch (Exception ex) {
System.out.println("lost a connection");
System.out.println(ex.getMessage().toString());
clientOutputStreams.remove(client);
}
}
}
public void tellEveryone(String message) {
// sends message to everyone connected to server
for(PrintWriter writer:clientOutputStreams){
try {
writer.println(message);
//pop("Sending: " + message);
writer.flush();
}
catch (Exception ex) {
System.out.println("error telling everyone");
}
}
}
public static void main(String[] args) {
new SSCCEServer().go();
}
public void go(){
clientOutputStreams = new ArrayList<PrintWriter>();
clientDataOutputStreams = new ArrayList<>();
try {
#SuppressWarnings("resource")
ServerSocket serverSock = new ServerSocket(5000);
while(true){
Socket clientSock = serverSock.accept();
PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
clientOutputStreams.add(writer);
clientDataOutputStreams.add(new DataOutputStream(clientSock.getOutputStream()));
Thread listener = new Thread(new ClientHandler(clientSock, writer));
listener.start();
}
}
catch (Exception ex)
{
System.out.println("error making a connection");
}
}
}
Sorry if it's really long but this is the minimal amount I could bring it to. Also it's not the whole thing because it misses the send text method but that doesn't affect the SSCCE. I've demonstrated the send method with the method 'tellEveryone' from the server side.
Also, the "\PNG\Night.png" is just an example, you can make your own folder and file in order to run the SSCCE.
What can I do to fix the closing of the socket after the file is send?
close all Objects in finally block (try - catch - finally)
you have got issue with Concurency in Swing, but there are three ways
a) proper ways
wrap code to the Runnable#Thread (easiest), have to wrap any changes to the Swing GUI into invokeLater()
use SwingWorker (implemented in standard ways), where methods publish, process and done quite guarante that all events are done on EDT
b) shortcuts, works but not proper of ways
wrap Swing GUI code into invokeLater() directly
The socket closes when you close the output stream. If you want to keep the socket open, do not close the stream. For reference have a look at SocketOutputStream.java
Related
I am programming a simple multi-threaded client/server chat system. Project requirements specify: "Connection only happens when the connect button is clicked. The disconnect button should disconnect the connection. A user should be able to connect, disconnect, re-connect at will." Basically, I have the connect button hooked-up and running. However, when I attempt to disconnect I get stuck in an infinite loop where the client side (on command line) infinitely prints "Sock closed", while the server side infinitely prints "Message read: null". This has lead me to look into all of my for(;;) loops to somehow close the connections within them, however I cannot figure out how to close the connection within those loops. Please help, this is my first socket programming project and I am super stumped on this one! Thanks all.
Client:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
public class ClientFrame extends Frame{
public ClientFrame(){
setSize(500,500);
setTitle("Chat Client");
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent We){
System.exit(0);
}
});
add(new ClientPanel(), BorderLayout.CENTER);
setVisible(true);
}
public static void main(String[] args){
new ClientFrame();
}
} // end ClientFrame
class ClientPanel extends Panel implements ActionListener, Runnable{
TextField tf;
TextArea ta;
List list;
Button connect, disconnect;
Socket socketToServer;
PrintWriter pw;
BufferedReader br;
Thread t;
String userName;
public ClientPanel(){
setLayout(new BorderLayout());
tf = new TextField();
ta = new TextArea();
list = new List();
connect = new Button("Connect");
disconnect = new Button("Disconnect");
Panel bPanel = new Panel();
bPanel.add(connect);
disconnect.setEnabled(false);
bPanel.add(disconnect);
tf.addActionListener(this);
add(tf, BorderLayout.NORTH);
add(ta, BorderLayout.CENTER);
add(list, BorderLayout.EAST);
add(bPanel, BorderLayout.SOUTH);
connect.addActionListener(this);
disconnect.addActionListener(this);
} // end ClientPanel constructor
public void actionPerformed(ActionEvent ae){
if (ae.getSource() == tf){
String temp = tf.getText();
pw.println(userName+": "+temp);
tf.setText("");
} else if (ae.getSource() == connect){
if(tf.getText() == null || tf.getText().equals("")){
ta.append("Must enter a name to connect\n");
}else {
userName = tf.getText();
connect.setEnabled(false);
disconnect.setEnabled(true);
tf.setText("");
try{
socketToServer = new Socket("127.0.0.1", 3000);
pw = new PrintWriter(new OutputStreamWriter
(socketToServer.getOutputStream()), true);
br = new BufferedReader(new InputStreamReader
(socketToServer.getInputStream()));
}catch(UnknownHostException uhe){
System.out.println(uhe.getMessage());
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
t = new Thread(this);
t.start();
pw.println(userName);
pw.println(userName +" has entered the chat.");
}else if (ae.getSource()== disconnect){
try{
t.interrupt();
socketToServer.close();
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
} // end actionPerformed
public void run(){
for(;;){
try{
String temp = br.readLine();
ta.append(temp + "\n");
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
} // end run
} // end ClientPanel
Server:
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.awt.*;
public class ThreadedServerWithPresence{
public static void main(String[] args){
ArrayList<ThreadedHandlerWithPresence> handlers;
try{
handlers = new ArrayList<ThreadedHandlerWithPresence>();
ServerSocket s = new ServerSocket(3000);
for(;;){
Socket incoming = s.accept( );
new ThreadedHandlerWithPresence(incoming,
handlers).start();
}
}catch (Exception e){
System.out.println(e);
}
}
}
class ThreadedHandlerWithPresence extends Thread{
Socket incoming;
ArrayList<ThreadedHandlerWithPresence> handlers;
PrintWriter pw;
BufferedReader br;
String userName;
public ThreadedHandlerWithPresence(Socket i,
ArrayList<ThreadedHandlerWithPresence> handlers){
incoming = i;
this.handlers = handlers;
handlers.add(this);
}
public void setUserName(String userName){
this.userName = userName;
}
public String getUserName(){
return userName;
}
public void run(){
try{
br = new BufferedReader(new InputStreamReader
(incoming.getInputStream()));
pw = new PrintWriter(new OutputStreamWriter
(incoming.getOutputStream()),true);
String firstLine = br.readLine();
setUserName(firstLine);
for(;;){
String temp = br.readLine();
System.out.println("Message read: " + temp);
for(int i = 0; i < handlers.size(); i++){
handlers.get(i).pw.println(temp);
}
}
}catch (Exception e){
System.out.println(e);
}finally{
handlers.remove(this);
}
}
}
Client
Your run method does not handle interruptions so the for loop does not end and it continues trying to receive messages.
You must add an action that can be interrupted and throws InterruptedException, Thread.sleep would be a good candidate in this case, also reducing CPU usage (You do not need to check for new messages every single moment).
try {
for (; ; ) {
try {
String temp = br.readLine();
ta.append(temp + "\n");
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
Thread.sleep(10);
}
} catch (InterruptedException e) {
System.out.println("Disconnected.");
}
Server
When br.readLine() returns null, that indicates the connection is closed by the client and you should stop receiving messages.
String temp = br.readLine();
if(temp == null)
break;
I am using Java sockets to create a simple chat room and using AWT component for the GUI. I have all functions of the chat room working, it sends and recieves messages to/from all users, etc... One requirement was to make a list that updates as users enter and leave the chat. I have this function working and my solution was to have my server print the current names of the handlers to a file and then the client grabs the names from the file and adds it to the list. To do this, I made a method that I put in a for(;;) loop so the list continuously updates as users enter/ leave the chat. These requirements all work fine...
MY PROBLEM: The next requirement states: "A user should be able to select a single user from the user list. While a name is selected, all messages sent will be private - only sent to that user." I cannot figure out how to get the selected name back to the server so that someone can send messages only to the username that is selected. Is this even possible with the way I handled creating my list? If so do you have any ideas on how to make this possible? I've been stumped on this for a few days and I am almost thinking at this point that it is not possible and I should rethink my logic for the list. If it is not possible, do you have any ideas for a better solution for my list?
Thank you!
Client file:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
public class ClientFrame extends Frame{
public ClientFrame(){
setSize(500,500);
setTitle("Chat Client");
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent We){
System.exit(0);
}
});
add(new ClientPanel(new FrameContainer(this)), BorderLayout.CENTER);
setVisible(true);
}
public static void main(String[] args){
new ClientFrame();
}
} // end ClientFrame
class ClientPanel extends Panel implements ActionListener, Runnable, ItemListener{
TextField tf;
TextArea ta;
List list;
Button connect, disconnect;
Socket socketToServer;
PrintWriter pw;
BufferedReader br;
Thread t;
String userName;
FrameContainer fc;
public ClientPanel(FrameContainer fc){
setLayout(new BorderLayout());
tf = new TextField();
ta = new TextArea();
list = new List();
this.fc = fc;
connect = new Button("Connect");
disconnect = new Button("Disconnect");
Panel bPanel = new Panel();
bPanel.add(connect);
disconnect.setEnabled(false);
bPanel.add(disconnect);
tf.addActionListener(this);
connect.addActionListener(this);
disconnect.addActionListener(this);
list.addItemListener(this);
add(tf, BorderLayout.NORTH);
add(ta, BorderLayout.CENTER);
add(list, BorderLayout.EAST);
add(bPanel, BorderLayout.SOUTH);
} // end ClientPanel constructor
public void actionPerformed(ActionEvent ae){
if (ae.getSource() == tf){
String temp = tf.getText();
pw.println(userName+": "+temp);
tf.setText("");
} else if (ae.getSource() == connect){
if(tf.getText() == null || tf.getText().equals("")){
ta.append("Must enter a name to connect\n");
}else {
setUsername(tf.getText());
fc.getFrame().setTitle(userName);
connect.setEnabled(false);
disconnect.setEnabled(true);
tf.setText("");
try{
socketToServer = new Socket("127.0.0.1", 3000);
pw = new PrintWriter(new OutputStreamWriter
(socketToServer.getOutputStream()), true);
br = new BufferedReader(new InputStreamReader
(socketToServer.getInputStream()));
}catch(UnknownHostException uhe){
System.out.println(uhe.getMessage());
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
t = new Thread(this);
t.start();
pw.println(userName);
pw.println(userName +" has entered the chat.");
}else if (ae.getSource() == disconnect){
try{
pw.println(userName +" has left the chat.");
list.removeAll();
fc.getFrame().setTitle("Chat Client");
t.interrupt();
br.close();
pw.close();
socketToServer.close();
connect.setEnabled(true);
disconnect.setEnabled(false);
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
} // end actionPerformed
public void itemStateChanged(ItemEvent ie){
if(ie.getStateChange() == ItemEvent.SELECTED){
String user = list.getSelectedItem();
}else if(ie.getStateChange() == ItemEvent.DESELECTED){
break;
}
} // end itemStateChanged
public void run(){
try {
for (;;) {
if(socketToServer.isClosed() == true) {
break;
}
setList();
try {
String temp = br.readLine();
ta.append(temp + "\n");
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
Thread.sleep(10);
}
} catch (InterruptedException e) {
System.out.println("Disconnected.");
}
} // end run
public void setList(){
list.removeAll();
try{
BufferedReader br = new BufferedReader(
new FileReader("onlinelist.txt"));
String line;
while((line = br.readLine()) != null){
this.list.add(line);
}
br.close();
}catch(FileNotFoundException fnfe){
System.out.println(fnfe.getMessage());
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
} // end setList
public void setUsername(String userName){
this.userName = userName;
}
public String getUsername(){
return userName;
}
} // end ClientPanel
// Container class to change title of frame
class FrameContainer{
ClientFrame f;
public FrameContainer(ClientFrame f){
setFrame(f);
}
public ClientFrame getFrame(){
return f;
}
public void setFrame(ClientFrame f){
this.f = f;
}
}
Server file:
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.awt.*;
public class ThreadedServerWithPresence{
public static void main(String[] args){
ArrayList<ThreadedHandlerWithPresence> handlers;
try{
handlers = new ArrayList<ThreadedHandlerWithPresence>();
ServerSocket s = new ServerSocket(3000);
for(;;){
Socket incoming = s.accept();
new ThreadedHandlerWithPresence(incoming,
handlers).start();
}
}catch (Exception e){
System.out.println(e);
}
}
}
class ThreadedHandlerWithPresence extends Thread{
Socket incoming;
ArrayList<ThreadedHandlerWithPresence> handlers;
PrintWriter pw;
BufferedReader br;
String userName;
ArrayList<String> list;
public ThreadedHandlerWithPresence(Socket i,
ArrayList<ThreadedHandlerWithPresence> handlers){
incoming = i;
this.handlers = handlers;
handlers.add(this);
list = new ArrayList<String>();
}
public void setUserName(String userName){
this.userName = userName;
}
public String getUserName(){
return userName;
}
public void run(){
try{
br = new BufferedReader(new InputStreamReader
(incoming.getInputStream()));
pw = new PrintWriter(new OutputStreamWriter
(incoming.getOutputStream()),true);
setUserName(br.readLine());
createList();
for(;;){
String temp = br.readLine();
if(temp == null)
break;
System.out.println("Message read: " + temp);
for(int i = 0; i < handlers.size(); i++){
handlers.get(i).pw.println(temp);
}
}
}catch (Exception e){
System.out.println(e);
}finally{
handlers.remove(this);
createList();
}
}
public void createList(){
try{
PrintWriter p = new PrintWriter(
new FileWriter("onlinelist.txt"));
for(int i = 0; i < handlers.size(); i++){
p.println(handlers.get(i).getUserName());
}
p.close();
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
}
so here is my code :
Server.java
import java.io.*;
import java.net.*;
import java.util.*;
class Server implements Runnable{
Socket connectionSocket;
public static Vector clients=new Vector();
public Server(Socket s){
try{
System.out.println("Client Got Connected " );
connectionSocket=s;
}catch(Exception e){e.printStackTrace();}
}
public void run(){
try{
BufferedReader reader =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
BufferedWriter writer=
new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()));
clients.add(writer);
while(true){
String data1 = reader.readLine().trim();
System.out.println("Received : "+data1);
for (int i=0;i<clients.size();i++){
try{
BufferedWriter bw= (BufferedWriter)clients.get(i);
bw.write(data1);
bw.write("\r\n");
bw.flush();
}catch(Exception e){e.printStackTrace();}
}
}
}catch(Exception e){e.printStackTrace();}
}
public static void main(String argv[]) throws Exception{
System.out.println("Threaded Chat Server is Running " );
ServerSocket mysocket = new ServerSocket(5555);
while(true){
Socket sock = mysocket.accept();
Server server=new Server(sock);
Thread serverThread=new Thread(server);
serverThread.start();
}
}
}
mychat.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class mychat implements Runnable
{
public JTextField tx;
public JTextArea ta;
public String login="Imed";
BufferedWriter writer;
BufferedReader reader;
public mychat(String l)
{
login=l;
ClientName z = new ClientName();
JFrame f=new JFrame(z.getName()+"'s Chat");
f.setSize(400,400);
JPanel p1=new JPanel();
p1.setLayout(new BorderLayout());
JPanel p2=new JPanel();
p2.setLayout(new BorderLayout());
tx=new JTextField();
p1.add(tx, BorderLayout.CENTER);
JButton b1=new JButton("Send");
p1.add(b1, BorderLayout.EAST);
ta=new JTextArea();
p2.add(ta, BorderLayout.CENTER);
p2.add(p1, BorderLayout.SOUTH);
f.setContentPane(p2);
try
{
Socket socketClient= new Socket("localhost",5555);
writer= new BufferedWriter(new OutputStreamWriter(socketClient.getOutputStream()));
reader =new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
}
catch(Exception e){e.printStackTrace();}
b1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
String s=login+" : "+tx.getText();
tx.setText("");
try
{
writer.write(s);
writer.write("\r\n");
writer.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
);
f.setVisible(true);
}
public void run()
{
try
{
String serverMsg="";
while((serverMsg = reader.readLine()) != null)
{
System.out.println("from server: " + serverMsg);
ta.append(serverMsg+"\n");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
startclient.java
public class startclient
{
public static void main(String [] args)
{
try
{
ClientName n = new ClientName();
mychat c=new mychat(n.getName());
Thread t1=new Thread(c);
t1.start();
}
catch(Exception e){e.printStackTrace();}
}
}
And last ClientName.java
import java.util.*;
public class ClientName
{
String name;
public String getName()
{
Scanner sc = new Scanner(System.in);
System.out.print ("Enter your name : ");
name = sc.nextLine();
return name;
}
}
So basically, i want to limit how many client that could join my server(which maximum is 10 client). And if there is another client that want to join the server after it is full, that client will be rejected so it cannot joined.
I think that's it, though if there are any other improvement in other areas at my code it will also be appreciated. Sorry for my bad english
*Oh and sorry since I forget to include it, but somehow when I start the client, it ask the name twice
You can fix main method in your server and add sayGoodBye() as follows:
private static final int CONNECTION_LIMIT = 10;
public static void main(String argv[]) throws Exception {
System.out.println("Threaded Chat Server is Running ");
ServerSocket mysocket = new ServerSocket(5555);
int socketCount = 0;
while (true) {
Socket sock = mysocket.accept();
Server server = new Server(sock);
if (socketCount++ < CONNECTION_LIMIT) {
Thread serverThread = new Thread(server);
serverThread.start();
} else {
// without starting a thread and notifying only new client
server.sayGoodbye();
}
}
}
public void sayGoodbye() throws IOException {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()))) {
writer.write("Sorry, new client connections are not accepted, bye for now");
} catch (Exception e) {
e.printStackTrace();
}
connectionSocket.close();
}
I have tried to make this program three times each time getting a little further. My program should work like this:
A client sends a message to the server which then sends the message to all connected clients (including the client that sent the message). When the clients receive the message they display it.
The problem I'm facing right now is that the server sends the message only to the client that sent it while the other clients receive nothing. I think this is happening because of the way I accept clients or at least it's somehow related to this
Here is my current code:
Client:
public class Client {
protected static JTextArea textArea = new JTextArea(20, 30);
protected static String sendMSG, getMSG;
public static void main(String[] args) throws IOException {
String hostName = args[0];
String Username = args[1];
boolean sending = true;
try (
Socket socket = new Socket(hostName, 1011);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
) {
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
//frame setup
JFrame frame = new JFrame("chat client");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//text area
JScrollPane scrollPane = new JScrollPane(textArea);
//text field
JTextField MSGText = new JTextField(5);
//"send" button
JButton sMSGB = new JButton("send");
sMSGB.setPreferredSize(new Dimension(60, 30));
sMSGB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
sendMSG = MSGText.getText();
MSGText.setText("");
out.println("<" + Username + ">: " + sendMSG);
}
});
//panel
JPanel p = new JPanel();
p.setLayout((new BoxLayout(p, BoxLayout.PAGE_AXIS)));
p.add(Box.createVerticalStrut(5));
p.add(scrollPane);
p.add(Box.createVerticalStrut(5));
p.add(MSGText);
p.add(Box.createVerticalStrut(5));
p.add(sMSGB);
p.add(Box.createVerticalStrut(5));
frame.getContentPane().add(p);
//set frame visible
frame.pack();
frame.setVisible(true);
System.out.println("<Client>: opened stream");
while(sending) {
/*while((sendMSG = stdIn.readLine()) != null) {
out.println("<" + Username + ">: " + sendMSG);
}*/
while((getMSG = in.readLine()) != null) {
System.out.println(getMSG);
textArea.append(getMSG + "\n");
//sending = false;
}
}
//sending = true;
}
}
}
Server:
public class Server {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(1011)) {
boolean listening = true;
while(listening) {
Socket socket = serverSocket.accept();
List<PrintWriter> outs = new CopyOnWriteArrayList<PrintWriter>();
new ServerThread(socket, outs).start();
System.out.println("opened thread");
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
ServerThread:
public class ServerThread extends Thread {
private final Socket socket;
private final List<PrintWriter> outs;
public ServerThread(Socket socket, List<PrintWriter> outs) {
super("ServerThread");
this.socket = socket;
this.outs = outs;
System.out.println("Opened outs: " + outs.size());
}
private void sendToAll(String msg) {
for(PrintWriter out: outs) {
out.println(msg);
}
}
public void run() {
try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
) {
System.out.println("stream opened");
outs.add(out);
String getMSGs;
while((getMSGs = in.readLine()) != null) {
//out.println(getMSGs);
sendToAll(getMSGs);
System.out.println("msg received and sent");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I hope you can help. Thanks in advance
You're reinitializing outs every time new client connects:
while(listening) {
Socket socket = serverSocket.accept();
List<PrintWriter> outs = new CopyOnWriteArrayList<PrintWriter>();
new ServerThread(socket, outs).start();
System.out.println("opened thread");
}
and basically spawning threads with empty outs. You need to keep the list of output streams (or sockets) outside the loop and build a way to signal already existing threads when you update the outs list (when a new client connects).
This is the code that i am using (its not mine)
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleChatClient {
JTextArea incoming;
JTextField outgoing;
BufferedReader reader;
PrintWriter writer;
Socket sock;
public void go() {
JFrame frame = new JFrame("Ludicrously Simple Chat Client");
JPanel mainPanel = new JPanel();
incoming = new JTextArea(15, 50);
incoming.setLineWrap(true);
incoming.setWrapStyleWord(true);
incoming.setEditable(false);
JScrollPane qScroller = new JScrollPane(incoming);
qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
outgoing = new JTextField(20);
JButton sendButton = new JButton("Send");
sendButton.addActionListener(new SendButtonListener());
mainPanel.add(qScroller);
mainPanel.add(outgoing);
mainPanel.add(sendButton);
frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
setUpNetworking();
Thread readerThread = new Thread(new IncomingReader());
readerThread.start();
frame.setSize(650, 500);
frame.setVisible(true);
}
private void setUpNetworking() {
try {
sock = new Socket("127.0.0.1", 5000);
InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(streamReader);
writer = new PrintWriter(sock.getOutputStream());
System.out.println("networking established");
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
public class SendButtonListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
try {
writer.println(outgoing.getText());
writer.flush();
}
catch (Exception ex) {
ex.printStackTrace();
}
outgoing.setText("");
outgoing.requestFocus();
}
}
public static void main(String[] args) {
new SimpleChatClient().go();
}
class IncomingReader implements Runnable {
public void run() {
String message;
try {
while ((message = reader.readLine()) != null) {
System.out.println("client read " + message);
incoming.append(message + "\n");
}
} catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
My question is in the incoming reader class
Why does this line---- while ((message = reader.readLine()) != null)
never return null?
Supposedly, the thread went to check this line and on the other side there are no messages for the client, then shouldn't the above line return null?
Can anyone explain a bit of what's going on? I do know about socket connections and all
I just want to know what's going on with getting incoming messages.
You are using blocking functions such as BufferedReader.readLine(). This will block until there is something to read. It won't "check the device and return null if nothing is returned".
You can check if there is any incoming data using BufferedReader.available() and call readLine() if the result is > 0.