Multiple Sockets Issue

D

Dan

Hello all,

I am having some serious issues trying to control multiple sockets.
Currently, I have it working so that the server piece can broadcast to
multiple clients, I just can't receive any messages when there are
more than one clients connected. I am probably explaining this
poorly, so I will let the code speak for itself:

package myxserver;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.io.*;
import java.awt.*;
import java.net.*;

public class TheXServer extends JFrame implements Runnable {

private final static int MAX_CONNECTIONS = 100;
private static boolean REMOVING = false;

protected WindowManager m_wm;
protected JTextArea m_consoletext, m_consolechat;
protected JTextField m_chatText;
protected JLabel m_status;

protected static int m_count;
protected static boolean m_connected;
protected static DataInputStream[] m_input; // input
array
protected static DataOutputStream[] m_output; // output
array
protected static Socket[] m_clients; // Client
array
protected static ServerSocket m_server; // this is
what waits for messages
protected static Thread[] m_listenthread; // an
array of listeners
protected static ConThread m_conthread; //
strangely, this needs to be here

public TheXServer() {
m_clients = new Socket[MAX_CONNECTIONS];
m_listenthread = new Thread[MAX_CONNECTIONS];
m_output = new DataOutputStream[MAX_CONNECTIONS];
m_input = new DataInputStream[MAX_CONNECTIONS];

setTitle("The X Server");
m_count = 0;
m_status = new JLabel("No Client");
JScrollPane scroller = new JScrollPane();
m_wm = new WindowManager(this);

getContentPane().setLayout(new BorderLayout());
getContentPane().add("Center", setupConsole());
getContentPane().add("South", m_status);

Dimension dim = getToolkit().getScreenSize();
setSize(520,350);
setLocation(dim.width/2-getWidth()/3, dim.height/2-getHeight()/2);
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
addWindowListener(l);
setVisible(true);
}

public JInternalFrame setupConsole() {
JInternalFrame console = new JInternalFrame ("The X Server",
false, false, false, false);
console.setBounds(2, 2, 500, 300);
console.setVisible(true);

JPanel chatPanel = new JPanel();
JLabel chatLabel = new JLabel(" CHAT ");
chatPanel.setLayout(new BorderLayout());

m_consoletext = new JTextArea();
m_consoletext.setPreferredSize(new Dimension(500, 50));
m_consoletext.setLineWrap(true);
m_consoletext.setText("Server Started.\nWaiting for client ...");
m_consoletext.setEditable(false);

m_consolechat = new JTextArea();
m_consolechat.setLineWrap(true);
m_consolechat.setEditable(false);

m_chatText = new JTextField();
m_chatText.addActionListener(new ChatAdapter());

JButton chatSend = new JButton("Send");
chatSend.addActionListener(new ChatAdapter());

JPanel sendPanel = new JPanel();

sendPanel.setLayout(new BorderLayout());
sendPanel.add("Center", m_chatText);
sendPanel.add("West", chatSend);

JScrollPane cscroller1 = new JScrollPane(m_consoletext);
JScrollPane cscroller2 = new JScrollPane(m_consolechat);

chatPanel.add("North", chatLabel);
chatPanel.add("Center", cscroller2);
chatPanel.add("South", sendPanel);

JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
true, cscroller1, chatPanel);
console.getContentPane().add(splitter);

try {
m_server = new ServerSocket(5000,500);
}
catch (Exception e) {
m_consoletext.append("\n"+e);
}
m_conthread = new ConThread();

return console;
}

public void run() {
while (m_connected) {
int i = 0;
try {
for (; i < m_count; i++)
processMessage(m_input.readUTF());
}
catch (Exception e) {
removeSocketConnections(i);
keepRunning(i);
}
}
}

public void keepRunning(int i) {
try {
for (; i < m_count; i++)
processMessage(m_input.readUTF());
}
catch (Exception e) {
removeSocketConnections(i);
keepRunning(i);
}
}

private static void removeSocketConnections(int x) {
REMOVING = true;

for (int i = x; i < m_count; i++) {
if (i + 1 < MAX_CONNECTIONS) {
m_input = m_input[i+1];
m_output = m_output[i+1];
m_clients = m_clients[i+1];
m_listenthread = m_listenthread[i+1];
}
else {
m_input = null;
m_output = null;
m_clients = null;
m_listenthread = null;
}
}
m_count--;
if (m_count <= 0) m_connected = false;

REMOVING = false;
}

public void processMessage(String s) {
if (s.startsWith("cc")) {
m_consolechat.append("CLIENT: " + s.substring(2) + "\n");
m_consolechat.setCaretPosition(m_consolechat.getText().length());
}
}

public static void main(String[] args) {
new TheXServer();
}

class ChatAdapter implements ActionListener {
public void actionPerformed (ActionEvent e) {
m_wm.sendMessage("cc" + m_chatText.getText());
m_consolechat.append("SERVER: " + m_chatText.getText() + "\n");
m_chatText.setText("");
}
}

class ConThread extends Thread {
ConThread() { start(); }
public void run() {
while (true) {
if (!REMOVING) {
try {
if (m_count+1 < MAX_CONNECTIONS) {
m_clients[m_count] = m_server.accept();
m_connected = true;
m_input[m_count] = new
DataInputStream(m_clients[m_count].getInputStream());
m_output[m_count] = new
DataOutputStream(m_clients[m_count].getOutputStream());
m_consoletext.append("\nStreams established ... ");
m_listenthread[m_count] = new Thread(TheXServer.this);
m_listenthread[m_count].start();
m_status.setText("Client Connected from: " +
m_clients[m_count].getInetAddress());
m_consoletext.append("\nClient Connected from: " +
m_clients[m_count].getInetAddress());
m_count++;
}
}
catch (Exception e) {
m_consoletext.append("\n" + e);
}
}
}
}
}

public class WindowManager extends DefaultDesktopManager {

protected JFrame m_desktop;

public WindowManager(JFrame desktop) { m_desktop = desktop; }
public WindowWatcher getWindowWatcher() { return null; }

public void sendMessage(String s) {
int i = 0;
try {
if (m_output != null) {
for (; i < m_count; i++)
m_output.writeUTF(s);
}
}
catch (Exception e) {
removeSocketConnections(i);
sendMessage(s, i);
}
}

public void sendMessage(String s, int i) {
try {
if (m_output != null) {
for (; i < m_count; i++)
m_output.writeUTF(s);
}
}
catch (Exception e) {
removeSocketConnections(i);
sendMessage(s, i);
}
}

public String getStringIndex(Component f) {
String s = f.toString();
while (s.length() < 3)
s = ("0").concat(s);
return s;
}

public String getString(int num) {
String s;
if (num < 0)
s = "" + (-num);
else
s = "" + num;
while (s.length() < 6)
s = ("0").concat(s);
if (num < 0)
s = "-" + s.substring(1, 6);
return s;
}

}
}


Now, this is my first time playing with sockets, so I am sure that
there are MANY problems with my code. This code is hacked together by
looking over several socket examples and pulling out all the
unnecessary code. My core problem that I need resolved is the fact
that when more than one client piece is connected to it, the server
never spits out a message. It seems to me that it is stuck in the Run
loop, but I can't really tell. By the way, the client piece looks
almost exactly like this, with some very minor differences ... like a
way to connect to the server and it doesn't have arrays of the input,
output and socket structures. If anyone has had much experience with
sockets and can point me to some good examples, I would be more than
happy to encorporate some more foreign code to try to get the jumble
to work. Thanks in advance.

Dan
 
S

Steve Horsley

Hello all,

I am having some serious issues trying to control multiple sockets.
Currently, I have it working so that the server piece can broadcast to
multiple clients, I just can't receive any messages when there are
more than one clients connected. I am probably explaining this
poorly, so I will let the code speak for itself:

public void run() {
while (m_connected) {
int i = 0;
try {
for (; i < m_count; i++)
processMessage(m_input.readUTF());
}
catch (Exception e) {
removeSocketConnections(i);
keepRunning(i);
}
}
}


I only had a quick look, but I see a problem there. Try changing the for
loop by adding a couple of lines, like this:
for (; i < m_count; i++)
{
System.out.pringln("Waiting for message from client " + i);
String msg = m_input.readUTF();
System.out.println("Got message from client " + i + ": " + msg);
processMessage(msg); }
}

Notice that I had to add a pair of braces. Note that you are _allowed_ to
use a single statement in a for() without braces, this is BAD practice. It
is all too easy to add a line later and not notice the missing braces,
which makes a real mess of the code. Best not leave the trap there in the
first place.

I think you will see that your code waits for a message from client 0
before ever looking at client 1. It will only work if your clients send
messages in strict rotation - unlikely. Before java 1.4, the only solution
was to leave a thread blocked on each input stream, and have the threads
put messages in a queue when they arrived. The main server theread could
then just read the queue. With 1.4+ you can use nio and select to be
notified, I think, but I haven't looked at nio yet.

Steve.
 
D

Dan

Hey Steve
Thanks for the reply. This is my first attempt at Sockets, so the
code is a bit sloppy.
I only had a quick look, but I see a problem there. Try changing the for
loop by adding a couple of lines, like this:
for (; i < m_count; i++)
{
System.out.pringln("Waiting for message from client " + i);
String msg = m_input.readUTF();
System.out.println("Got message from client " + i + ": " + msg);
processMessage(msg); }
}

I think you will see that your code waits for a message from client 0
before ever looking at client 1. It will only work if your clients send
messages in strict rotation - unlikely. Before java 1.4, the only solution
was to leave a thread blocked on each input stream, and have the threads
put messages in a queue when they arrived. The main server theread could
then just read the queue. With 1.4+ you can use nio and select to be
notified, I think, but I haven't looked at nio yet.


You know, I think you are right and here is why. When there is only
one client, everything works fine. However, once more than one client
connect no messages get displayed .. not even from the first. But,
once the first client to connect gets closed all the messages that
were sent by the clients all pop up on the server in the correct
order. But, then the messages don't work again, regardless of how
many clients are connected.

I have tried the System.out messages within the block of code above
they never get displayed ... only when there is one client connected
from the start.

There are lots of other little problems ... but again, I just need to
get the messages sent. How do people generally solve this type of
problem? I was thinking of keeping track of each connection in a
class stored in an arrayList, Then sending messages to one of them at
a time rather than as a broadcast. Also, setting up seperate threads
for each structure to monitor their own individual connection for all
messages coming in. But I would prefer to have the listener in one
place if possible ... or is this just an impossible dream?

Thanks again for your help
Dan
 
D

Dan

Ok, I fixed it. The follwoing code seems to be working pretty well.
So far, I haven't noticed anything major ... but here goes:

package mynextxserver;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.io.*;
import java.awt.*;
import java.util.*;
import java.net.*;

public class MyXServerAdvanced extends JFrame implements
ActionListener {

private ArrayList connectionList = new ArrayList();
protected JLabel m_status;
protected JTextArea m_consoletext, m_consolechat;
protected JTextField m_chatText;

protected static int m_count;
protected static ConThread m_conthread;
protected static ServerSocket m_server;
protected static Socket m_client;

public MyXServerAdvanced() {
setTitle("The X Server");
m_count = 0;
m_status = new JLabel("No Client");
JScrollPane scroller = new JScrollPane();

getContentPane().setLayout(new BorderLayout());
getContentPane().add("Center", setupConsole());
getContentPane().add("South", m_status);

Dimension dim = getToolkit().getScreenSize();
setSize(520,350);
setLocation(dim.width/2-getWidth()/3, dim.height/2-getHeight()/2);
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
};
addWindowListener(l);
setVisible(true);
}

public JInternalFrame setupConsole() {
JInternalFrame console = new JInternalFrame ("The X Server",
false, false, false, false);
console.setBounds(2, 2, 500, 300);
console.setVisible(true);

JPanel chatPanel = new JPanel();
JLabel chatLabel = new JLabel(" CHAT ");
chatPanel.setLayout(new BorderLayout());

m_consoletext = new JTextArea();
m_consoletext.setPreferredSize(new Dimension(500, 50));
m_consoletext.setLineWrap(true);
m_consoletext.setText("Server Started.\nWaiting for client ...");
m_consoletext.setEditable(false);

m_consolechat = new JTextArea();
m_consolechat.setLineWrap(true);
m_consolechat.setEditable(false);

m_chatText = new JTextField();
m_chatText.addActionListener(this);

JButton chatSend = new JButton("Send");
chatSend.addActionListener(this);

JPanel sendPanel = new JPanel();

sendPanel.setLayout(new BorderLayout());
sendPanel.add("Center", m_chatText);
sendPanel.add("West", chatSend);

JScrollPane cscroller1 = new JScrollPane(m_consoletext);
JScrollPane cscroller2 = new JScrollPane(m_consolechat);

chatPanel.add("North", chatLabel);
chatPanel.add("Center", cscroller2);
chatPanel.add("South", sendPanel);

JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
true, cscroller1, chatPanel);
console.getContentPane().add(splitter);

try {
m_server = new ServerSocket(5000,500);
}
catch (Exception e) {
m_status.setText(""+e);
m_consoletext.append("\n"+e);
}
m_conthread = new ConThread();

return console;
}

public void processMessage(String s) {
if (s.startsWith("cc")) {
m_consolechat.append("CLIENT: " + s.substring(2) + "\n");
m_consolechat.setCaretPosition(m_consolechat.getText().length());
}
}

public void actionPerformed(ActionEvent e) {
int i = 0;
try {
for (; i < m_count; i++) {
ServerConnection con =
(ServerConnection)connectionList.get(i);
con.sendMessage("cc" + m_chatText.getText());
}
}
catch (Exception ex) {
connectionList.remove(i);
m_count--;
keepSending(i);
}
m_consolechat.append("SERVER: " + m_chatText.getText() + "\n");
m_chatText.setText("");
}

public void keepSending(int i) {
try {
for (; i < m_count; i++) {
ServerConnection con =
(ServerConnection)connectionList.get(i);
con.sendMessage("cc" + m_chatText.getText());
}
}
catch (Exception ex) {
connectionList.remove(i);
m_count--;
keepSending(i);
}
}

class ConThread extends Thread {
ConThread() { start(); }
public void run() {
while (true) {
try {
m_client = m_server.accept();
ServerConnection newCon = new ServerConnection(m_client,
new DataInputStream(m_client.getInputStream()),
new DataOutputStream(m_client.getOutputStream()),
"CLIENT" + m_count++);
connectionList.add(newCon);

m_consoletext.append("\nStreams established ... \nClient
Connected from: " + m_client.getInetAddress());
m_status.setText("New Client Connected from: " +
m_client.getInetAddress());
}
catch (Exception e) {
m_status.setText("" + e);
m_consoletext.append("\n" + e);
}
}
}
}

class ServerConnection extends Thread {

protected String TAG;
protected Socket m_clients;
protected Thread m_listenthread;
protected DataInputStream m_input;
protected DataOutputStream m_output;

ServerConnection(Socket sock, DataInputStream in, DataOutputStream
out, String tag) {
m_clients = sock;
m_input = in;
m_output = out;
m_listenthread = new Thread(ServerConnection.this);
m_listenthread.start();
TAG = tag;
}

public void run() {
while (true) {
try {
String s = m_input.readUTF();
if (s.startsWith("cc")) {
m_consolechat.append(TAG + ": " + s.substring(2) + "\n");
m_consolechat.setCaretPosition(m_consolechat.getText().length());
}
}
catch (Exception e) { m_status.setText("" + e); }
}
}

public void sendMessage(String s) throws Exception {
m_output.writeUTF(s);
}
}

public static void main(String[] args) { new MyXServerAdvanced(); }
}



And ... just in case you want to see the client piece:

package myxclient;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.io.*;
import java.awt.*;
import java.net.*;

public class TheXClient extends JFrame implements Runnable {

protected int m_count;
protected JButton m_connect;
protected JTextArea m_consoletext, m_consolechat;
protected JTextField m_text, m_chatText;;
protected boolean m_connected;
protected JLabel m_status;
protected DataInputStream m_input;
protected DataOutputStream m_output;
protected Socket m_client;
protected Thread m_listenthread;

public TheXClient() {
setTitle("The X Client");
m_count = 0;
m_status = new JLabel("Not Connected");

m_connect = new JButton("Connect");
m_connect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (m_listenthread == null) {
Thread connector = new Thread() {
public void run() {
try {
m_consoletext.append("\nTrying " + m_text.getText() +
" ... ");
m_client = new
Socket(InetAddress.getByName(m_text.getText()), 5000);
m_input = new
DataInputStream(m_client.getInputStream());
m_output = new
DataOutputStream(m_client.getOutputStream());
m_connected = true;
m_listenthread = new Thread(TheXClient.this);
m_listenthread.start();
m_consoletext.append("\nStreams established ... ");
m_status.setText("Connected to " + m_text.getText());
m_connect.setEnabled(false);
}
catch (Exception e) {
m_consoletext.append("\n" + e);
}
}
};
connector.start();
}
}
});

JPanel XPanel = new JPanel();
XPanel.setLayout(new BorderLayout());
JLabel h1 = new JLabel("Connect to: ", SwingConstants.CENTER);
m_text = new JTextField(15);
XPanel.add("North", h1);
XPanel.add("Center", m_text);
XPanel.add("East", m_connect);

JPanel upperPanel = new JPanel();
upperPanel.setLayout(new BorderLayout());
upperPanel.add("Center", XPanel);

getContentPane().setLayout(new BorderLayout());
getContentPane().add("North", upperPanel);
getContentPane().add("Center", setupConsole());
getContentPane().add("South", m_status);

Dimension dim = getToolkit().getScreenSize();
setSize(520,400);
setLocation(dim.width/2-getWidth()/3, dim.height/2-getHeight()/2);
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
addWindowListener(l);
setVisible(true);
}

public JInternalFrame setupConsole() {
JInternalFrame console = new JInternalFrame ("The X Client",
false, false, false, false) {
int TAG = m_count;
public String toString() {
return "" + TAG;
}
};
console.setBounds(2, 2, 500, 300);
console.setVisible(true);

JPanel chatPanel = new JPanel();
JLabel chatLabel = new JLabel(" CHAT ");
chatPanel.setLayout(new BorderLayout());

m_consoletext = new JTextArea();
m_consoletext.setPreferredSize(new Dimension(500, 50));
m_consoletext.setLineWrap(true);
m_consoletext.setText("Client Started ...");
m_consoletext.setEditable(false);

m_consolechat = new JTextArea();
m_consolechat.setLineWrap(true);
m_consolechat.setEditable(false);

m_chatText = new JTextField();
m_chatText.addActionListener(new ChatAdapter());

JButton chatSend = new JButton("Send");
chatSend.addActionListener(new ChatAdapter());

JPanel sendPanel = new JPanel();

sendPanel.setLayout(new BorderLayout());
sendPanel.add("Center", m_chatText);
sendPanel.add("West", chatSend);

JScrollPane cscroller1 = new JScrollPane(m_consoletext);
JScrollPane cscroller2 = new JScrollPane(m_consolechat);

chatPanel.add("North", chatLabel);
chatPanel.add("Center", cscroller2);
chatPanel.add("South", sendPanel);

JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
true, cscroller1, chatPanel);
console.getContentPane().add(splitter);

return console;
}

public void run() {
while (m_connected) {
try {
processMessage(m_input.readUTF());
}
catch (Exception e) {
m_consoletext.append("\n" + e);
m_connected = false;
}
}
}

public void processMessage(String s) {
if (s.startsWith("cc")) {
m_consolechat.append("SERVER: " + s.substring(2) + "\n");
m_consolechat.setCaretPosition(m_consolechat.getText().length());
}
else
System.out.println("well .. i can't imagine why im here");
}

public void sendMessage(String s) {
try {
if (m_output != null)
m_output.writeUTF(s);
}
catch (Exception e) {}
}

public static void main(String[] args) {
new TheXClient();
}

class ChatAdapter implements ActionListener {
public void actionPerformed (ActionEvent e) {
sendMessage("cc" + m_chatText.getText());
m_consolechat.append("Client: " + m_chatText.getText() + "\n");
m_chatText.setText("");
}
}
}



Keep in mind, they are very rough .... I haven't fine tuned them yet.
But, they work ... so thanks to all that helped.

Enjoy
 
S

soft-eng

Looks like you are mixing up two ideas -- you do have
an independent thread for each of your clients, but you
are still trying to read clients sequentially.
Each of your thread needs to be responsible for only
its own client, instead of doing a "readUTF()" for all
clients ranging from 0 to m_count. Otherwise you
have multiple threads reading sequentially from
all the clients.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,170
Latest member
Andrew1609
Top