i'm making GUI for my java server program but when i launch it program show white JFrame and doesn't load component into frame.
Here there's code:
public ServerFrame() throws SQLException, ClassNotFoundException, IOException {
initComponents();
server = new ServerSocket(4444);
textList.setText("Waiting for client to connect...");
SimpleDataSource.init("database.properties");
net = new Network();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable(){
#Override
public void run(){
ServerFrame sf;
try{
sf = new ServerFrame();
sf.setVisible(true);
s = server.accept();
InetAddress clientAddress = s.getInetAddress();
textList.setText("Incoming connection from: " + clientAddress.getHostName() + "[" + clientAddress.getHostAddress() + "]\n");
ServiceClass service = new ServiceClass(s,net);
Thread t = new Thread(service);
t.start();
}catch (SQLException | ClassNotFoundException | IOException ex){
Logger.getLogger(ServerFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
when program launch it doesn't show me component into frame because it wait client to connect. When a client connect it shows correctly all components..how can i show all component without client connected?
thanks
I do not know what these lines do exactly, so that happens below might also apply to them.
SimpleDataSource.init("database.properties");
net = new Network();
The main problem is most likely that this line: server = new ServerSocket(4444); hangs everything until the client connects, which makes the main thread of your application continue execution and thus display everything.
To fix this, launch the server on a seperate Thread.
Something like so:
new Thread(new Runnable()
{
#Override
public void run()
{
server = new ServerSocket(4444);
}
}).start();
You will need to declare your server final, so that it can be accessed from within the run method.
Related
I am writing a Java client/server GUI application using sockets and here is the problem:
I have a button to start listening for a specified port:
button actionPerformed method
private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {
int port = Integer.parseInt(portTextfield.getText(), 10);
try {
socket.listen(port);
} catch (IOException ex) {
}
}
Here is the socket.listen method
public static void listen() throws IOException {
ServerSocket ss = new ServerSocket(port);
while (true)
new socket(ss.accept());
}
"socket" class extends "Thread"
So after ss.accept() returns a value it creates new socket instance in separate thread.
After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop. How can I avoid that?
You have two pitfalls in your design:
ss.accept() is a blocking call so your UI will freeze until there is an incoming connection
Never run while(true) loops in the EDT.
Instead do the following:
When the button is clicked create a thread that will start listening for incoming connections.
Whenever you have an incoming connection, create another thread that will take the incoming client connection and deal with it.
as long as your
new socket(ss.accept());
returns immediately, you only need to change your
while (true)
this puts the EDT (Event Dispatch Thread) into an infinite loop and your GUI becomes irresponsive. So, delete this line.
If you can't then use the SwingWorker class ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List)
Create a nested class that extents SwingWorker. Just call a swingWoker.execute(); (after you have created its object) in your listenButtonActionPerformed(java.awt.event.ActionEvent evt) method.
See the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Never create a new thread and run it from from the Swing EDT
Check this out: http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html
1) If you are writing GUI application may be in Swing never call
blocking method in Event dispatcher thread or in the event handler.
for example if you are reading a file or opening a network connection
when a button is clicked don't do that on actionPerformed() method,
instead just create another worker thread to do that job and return
from actionPerformed(). this will keep your GUI responsive, but again
it depends upon design if the operation is something which requires
user to wait than consider using invokeAndWait() for synchronous
update.
Using multiple threads: http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html
You will need to use Multi-Threading. If I where you, I would separate the GUI code and the server code and when the button is pressed, I simply launch the Server code as a new Thread.
Your code is freezing the GUI basically because all events are executed on the Event Dispatcher Thread (EDT) which is the thread which takes care of all your GUI stuff and respective events. If you either block it, stop it or throw in loops it will affect on its performance.
Try these...
1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.
`Socket s = new Socket();`
`s.connect(new InetSocketAddress("ip_addr",port_nos),1000);`
2. And Secondly always keep the Non-UI work out of Your UI thread..
Here is my Example of Server - Client Communication..
Client side code:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket();
s.connect(new InetSocketAddress("127.0.0.1", 4444),1000);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server side code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}
I have Java client which connects to my Java server. Java clients are in different networks and are running on MTX-GTW (Embedded Linux).
When I start server and the clients everything works fine, and clients are sending data every 1 minute. But after a day or more, clients will stop sending data one by one. Time varies.
But rest of the program runs fine, since program uses HTTP to communicate with some API and there we are still receiving data.
I checked server debug output and I can't see any errors or exceptions. I tried restarting the server and it also didn't help. My next step will be, to have similar client on my PC, so that I can see debug log, but that can take some time. So would any of you have any idea what could be the problem?
I use Java 7, here I call method to open socket:
static private void createHomeCallTimer()
{
new java.util.Timer().schedule(
new java.util.TimerTask()
{
public void run()
{
log.info("homeCall run");
Main main = new Main();
String data = "xxxxx";
try
{
log.info("Start of HOMECALL with data: " + data);
new TCPClient().openSocketAndSendData(data);
createHomeCallTimer();
} catch (Exception e)
{
log.error("Exception on homeCall: " + e);
createHomeCallTimer();
}
}
},
HOMECALLTIME
);
}
And this is client which is called by that method:
public class TCPClient
{
public void openSocketAndSendData(String data) throws IOException
{
Logger log = Logger.getLogger(TCPClient.class);
String ip = "xx.xx.xx.xx";
int port = 9000;
Socket clientSocket = new Socket(ip, port);
log.info("SOCKET TO IKU SERVER OPENED");
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
log.info("IKU SERVER: " + inFromServer.readLine());
outToServer.writeBytes(data);
clientSocket.close();
log.info("SOCKET CLOSED");
}
}
After you said that device has really small memory, then here's my suspect.
I didn't run your code but stripped it a little and speed it up to see what happens.
Here's code:
public class Main {
private static final int HOMECALLTIME = 10;
static private void createHomeCallTimer() {
new java.util.Timer().schedule(new java.util.TimerTask() {
public void run() {
// log.info("homeCall run");
// Main main = new Main();
String data = "xxxxx";
System.out.println(data);
// log.info("Start of HOMECALL with data: " + data);
// new TCPClient().openSocketAndSendData(data);
createHomeCallTimer();
}
}, HOMECALLTIME);
}
public static void main(String[] args) {
createHomeCallTimer();
}
}
And here's output after few minutes:
Exception in thread "Timer-21424" java.lang.OutOfMemoryError: unable
to create new native thread
at java.lang.Thread.start0(Native Method) at
java.lang.Thread.start(Thread.java:714) at
java.util.Timer.(Timer.java:160) at
java.util.Timer.(Timer.java:132) at
pkg.Main.createHomeCallTimer(Main.java:13) at
pkg.Main.access$0(Main.java:12) at pkg.Main$1.run(Main.java:22) at
java.util.TimerThread.mainLoop(Timer.java:555) at
java.util.TimerThread.run(Timer.java:505)
I suspect recursive call prevents freeing up memory and you run out of memory on your device. That's just a suspicion, but doesn't quite fit in a comment.
Here's the same code without recursion, using Timer:
static private void createHomeCallTimer() {
new java.util.Timer().scheduleAtFixedRate(new java.util.TimerTask() {
public void run() {
// log.info("homeCall run");
// Main main = new Main();
String data = "xxxxx";
System.out.println(data);
// log.info("Start of HOMECALL with data: " + data);
// new TCPClient().openSocketAndSendData(data);
}
}, 0, HOMECALLTIME);
}
I'm trying to create a program which will determine if the server is connected, down or disconnected.
I need to make the client automatically connect to the server when it's open.
Questions:
1. How can I continuously ping the server, to determine if the server is up?
2. Why is it when I click the button the server can only receive once.
3. Determine when the Server is disconnected
here's my code:
SERVER
public Server()
{
super("Server");
server.setLayout(new BorderLayout());
main.setLayout(new BorderLayout());
top.setLayout(new BorderLayout());
bot.setLayout(new BorderLayout());
console.setEditable(false);
console.setFont(new Font("Courier New",Font.PLAIN,14));
console.setBackground(Color.BLACK);
console.setForeground(Color.WHITE);
bot.add(console);
top.add(btnReply,BorderLayout.EAST);
top.add(queryline,BorderLayout.CENTER);
main.add(top,BorderLayout.NORTH);
main.add(bot,BorderLayout.CENTER);
add(main);
}
private void runServer() throws IOException
{
int port = 25000;
ServerSocket serverSocket = new ServerSocket(port);
console.setText("Server is Up and listening to the port: "+port+"\n");
System.out.println("Server is Up and listening to the port: "+port+"\n");
while(true)
{
Thread thread = new Thread(new Handler(socket));
thread.start();
}
}
public static void main(String args[])
{
Server f=new Server();
f.setVisible(true);
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try
{
f.runServer();
}catch(IOException ex)
{
//JOptionPane.showMessageDialog(null,ex.getMessage());
}
}
#Override
public void actionPerformed(ActionEvent e)
{
}
}
class Handler implements Runnable
{
private Socket socket;
public Handler(Socket socket){
this.socket = socket;
}
public void run()
{
// You may need to add a repeat and exit clause here...
Server f=new Server();
try
{
InputStreamReader ir = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(ir);
String message = br.readLine();
System.out.println(message);
String[] received=message.split("~");
f.console.append(received[1]+": requesting for "+received[0]+"\n");
System.out.println(received[1]+": requesting for "+received[0]+"\n");
}catch(IOException ex)
{
ex.printStackTrace();
}
}
}
CLIENT
public class Branch extends JFrame
{
private static Socket socket;
JPanel main=new JPanel();
JPanel top=new JPanel();
JPanel bot=new JPanel();
JButton btnItem=new JButton("item");
JButton btnGlstock=new JButton("glstock");
JTextArea console=new JTextArea();
JScrollPane scrollv=new JScrollPane(console);
ActionListener item=new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
String ip="";
String send="";
try
{
ip=InetAddress.getLocalHost().getHostAddress();
send="item~"+ip;
request(send);
}catch(Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
}
}
};
ActionListener glstock=new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
String ip="";
String send="";
try
{
ip=InetAddress.getLocalHost().getHostAddress();
send="glstock~"+ip;
request(send);
}catch(Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
}
}
};
private void request(String send)
{
try
{
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(send+"\n");
bw.flush();
}catch(Exception ex)
{
ex.printStackTrace();
}
}
public Branch()
{
super("Branch");
scrollv.setAutoscrolls(true);
main.setLayout(new BorderLayout());
top.setLayout(new FlowLayout());
top.add(btnItem);
top.add(btnGlstock);
btnItem.addActionListener(item);
btnGlstock.addActionListener(glstock);
bot.setLayout(new BorderLayout());
console.setEditable(false);
console.setForeground(Color.white);
console.setBackground(Color.black);
bot.add(scrollv,BorderLayout.CENTER);
main.add(top,BorderLayout.NORTH);
main.add(bot,BorderLayout.CENTER);
add(main);
}
private void connect2Server() throws IOException
{
Timer timer=new Timer(5000,checkPing);
try
{
socket = new Socket(IP,port);
console.append("You are now Connected to the Server\r\n");
//timer.start();
socket.setSoTimeout(5000);
InputStreamReader isr=new InputStreamReader(socket.getInputStream());
isr.read();
}
catch(SocketTimeoutException ex)
{
ex.printStackTrace();
}
catch(IOException ex)
{
console.append("Server is offline\r\n");
ex.printStackTrace();
}
connect2Server();
}
public static void main(String args[])
{
Branch frame=new Branch();
frame.setVisible(true);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.connect2Server();
frame.connectDatabase();
}
}
How can I continuously ping the server, to determine if the server is up?
Use a timer of some sort to schedule a regular callback and make your test there. Pinging a server (in this context) could be as simply as trying to make a connection to it...
You could also use InetAddress#isReachable as well...
Why is it when I click the button the server can only receive once
Because the server is no longer processing your connection. Take a look at your server code...
while(true)
{
//^Reading the message from the client
// Wait for a NEW client connection
socket = serverSocket.accept();
// Process request...
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
System.out.println(message);
String[] received=message.split("~");
console.append(received[1]+": requesting for "+received[0]+"\n");
// ... No longer monitoring for new content...
}
serverSocket.accept(); is waiting for a NEW client connection, not monitoring existing connections.
What you should be doing is spawning of a Thread of some kind, passing a reference to the client Socket connection and processing it there, within it's own loop...providing either a timeout or possible exit condition so that the socket and thread can be closed...
Determine when the Server is disconnected
Basically, if you try and send something to the server (or client), it will throw some kind of Exception, which is a pretty good indication that the connection has disconnected for some reason.
You could, also, use some kind of timer to periodically send a "health" check message to the server, but, you would need to ensure that you are synchronizing your communications, so two (client side) threads don't try and send a message at the same time.
Side Note
Your current code will block the Event Dispatching Thread when sending messages. This might not be a big thing when you test locally, but, depending on the speed of the connection and the ability for the server to respond in a timely manner, could lead to your UI appearing to "freeze" for a second or two (or longer)
Have a look at Concurrency in Swing for more details
Updated with example
In order to allow you server to be able to handle multiple client connections, you need to spawn a new thread for each new connection, for example...
private void runServer() throws IOException
{
int port = 25000;
ServerSocket serverSocket = new ServerSocket(port);
console.setText("Server is Up and listening to the port: "+port+"\n");
System.out.println("Server is Up and listening to the port: "+port+"\n");
while(true)
{
Socket socket = serverSocket.accept();
Thread thread = new Thread(new Handler(socket));
thread.start();
}
}
Then in your "client socket handler", you need to setup a loop which will keep reading from the client socket until something goes wrong or the client requests that the communication been terminated, for example...
class Handler implements Runnable
{
private Socket socket;
public Handler(Socket socket){
this.socket = socket;
}
public void run()
{
// You may need to add a repeat and exit clause here...
try
{
boolean keepRunning = true;
while (keepRunning) {
InputStreamReader ir = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(ir);
String message = br.readLine();
System.out.println(message);
String[] received=message.split("~");
System.out.println(received[1]+": requesting for "+received[0]+"\n");
// Check for a valid "exit" state and change keepRunning
// if the client want's to disconnect...
}
}catch(IOException ex)
{
ex.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
} catch (Exception exp) {
}
}
}
}
Also, make sure you are closing your resources properly ;)
How can I continuously ping the server, to determine if the server is up?
Keep trying to connect to it, with a sleep and loop if you fail.
Why is it when I click the button the server can only receive once.
Because your server only reads once per connection. The Handler.run() method needs to loop until readLine() returns null or an exception occurs.
Determine when the Server is disconnected
A read() would return -1, readLine() would return null, any other readXXX() will throw EOFException. However your client never reads at all. You should probably adjust your application protocol so that the server replies to each send. Otherwise you will just have to wait until an IOException occurs when sending, which could take several iterations before it happens due to TCP buffering.
Other notes:
Don't create new streams per send. Use the same streams, readers, writers, for the life of the socket.
Don't execute network code in the event thread. Use a separate thread.
I am writing a Java client/server GUI application using sockets and here is the problem:
I have a button to start listening for a specified port:
button actionPerformed method
private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {
int port = Integer.parseInt(portTextfield.getText(), 10);
try {
socket.listen(port);
} catch (IOException ex) {
}
}
Here is the socket.listen method
public static void listen() throws IOException {
ServerSocket ss = new ServerSocket(port);
while (true)
new socket(ss.accept());
}
"socket" class extends "Thread"
So after ss.accept() returns a value it creates new socket instance in separate thread.
After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop. How can I avoid that?
You have two pitfalls in your design:
ss.accept() is a blocking call so your UI will freeze until there is an incoming connection
Never run while(true) loops in the EDT.
Instead do the following:
When the button is clicked create a thread that will start listening for incoming connections.
Whenever you have an incoming connection, create another thread that will take the incoming client connection and deal with it.
as long as your
new socket(ss.accept());
returns immediately, you only need to change your
while (true)
this puts the EDT (Event Dispatch Thread) into an infinite loop and your GUI becomes irresponsive. So, delete this line.
If you can't then use the SwingWorker class ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List)
Create a nested class that extents SwingWorker. Just call a swingWoker.execute(); (after you have created its object) in your listenButtonActionPerformed(java.awt.event.ActionEvent evt) method.
See the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Never create a new thread and run it from from the Swing EDT
Check this out: http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html
1) If you are writing GUI application may be in Swing never call
blocking method in Event dispatcher thread or in the event handler.
for example if you are reading a file or opening a network connection
when a button is clicked don't do that on actionPerformed() method,
instead just create another worker thread to do that job and return
from actionPerformed(). this will keep your GUI responsive, but again
it depends upon design if the operation is something which requires
user to wait than consider using invokeAndWait() for synchronous
update.
Using multiple threads: http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html
You will need to use Multi-Threading. If I where you, I would separate the GUI code and the server code and when the button is pressed, I simply launch the Server code as a new Thread.
Your code is freezing the GUI basically because all events are executed on the Event Dispatcher Thread (EDT) which is the thread which takes care of all your GUI stuff and respective events. If you either block it, stop it or throw in loops it will affect on its performance.
Try these...
1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.
`Socket s = new Socket();`
`s.connect(new InetSocketAddress("ip_addr",port_nos),1000);`
2. And Secondly always keep the Non-UI work out of Your UI thread..
Here is my Example of Server - Client Communication..
Client side code:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket();
s.connect(new InetSocketAddress("127.0.0.1", 4444),1000);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server side code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}
I am new to Socket programming in Java and was trying to understand if the below code is not a wrong thing to do. My question is:
Can I have multiple clients on each thread trying to connect to a server instance in the same program and expect the server to read and write data with isolation between clients"
public class Client extends Thread
{
...
void run()
{
Socket socket = new Socket("localhost", 1234);
doIO(socket);
}
}
public class Server extends Thread
{
...
void run()
{
// serverSocket on "localhost", 1234
Socket clientSock = serverSocket.accept();
executor.execute(new ClientWorker(clientSock));
}
}
Now can I have multiple Client instances on different threads trying to connect on the same port of the current machine?
For example,
Server s = new Server("localhost", 1234);
s.start();
Client[] c = new Client[10];
for (int i = 0; i < c.length; ++i)
{
c.start();
}
Yes, however only one client will be able to connect per thread execution as written.
You can just put your server run() inside a while true loop to let multiple clients connect.
Depending on the executor, they will execute either in series or parallel.
public class Server extends Thread
{
...
void run()
{
while(true){
// serverSocket on "localhost", 1234
Socket clientSock = serverSocket.accept();
executor.execute(new ClientWorker(clientSock));
}
}
}
As long as you only have one object trying to bind the port for listening, then there's no problem with multiple clients connecting.
In this example, your Server accepts and handles one client connection at a time. You can have as many Clients as you want attempting to connect, but only one at a time will be handled.
It is not apparent whether your executor logic is multithreaded, since you didn't provide the implementation. If the executor delegates to a threadpool or something like that, you would need to make sure that your ClientWorker is thread-safe, as you will have multiple instances executing in parallel.
I am of course assuming that your Client is thread-safe as well, since your question is only concerning the Server.
Yes, it doesn't matter whether your clients are local or remote. The important thing in your example is that ClientWorker is thread-safe, as your server will have multiple instances of that class (one for each client connection).
So. To begin:
You can accept more clients with one serversocket, because you accept only one in the run-method. You have just to call accept() a second time.
Then, you in your for loop: first you have to create each time a new Client object. Then you can call c[i].start(); and not c.start().
Now can I have multiple Client
instances on different threads trying
to connect on the same port of the
current machine?
Yes you can. Just create new Threads and run them. This should work perfectly.
expect the server to read and write
data with isolation between clients
You can use your experience of the basic IO techniques like with file-io:
OutputStream os = socket.getOutputStream();
PrintStream pw = new PrintStream(os, true); // Or PrintWriter, I don't know what the best one is.
pw.println("Hello, other side of the connection!");
And for reading use a BufferedReader.
You can try something on these lines
public class MultiThreadServer extends Application {
// Text area for displaying contents
private TextArea ta = new TextArea();
// Number a client
private int clientNo = 0;
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a scene and place it in the stage
Scene scene = new Scene(new ScrollPane(ta), 450, 200);
primaryStage.setTitle("MultiThreadServer"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
new Thread( () -> {
try {
// Create a server socket
ServerSocket serverSocket = new ServerSocket(8000);
ta.appendText("MultiThreadServer started at "
+ new Date() + '\n');
while (true) {
// Listen for a new connection request
Socket socket = serverSocket.accept();
// Increment clientNo
clientNo++;
Platform.runLater( () -> {
// Display the client number
ta.appendText("Starting thread for client " + clientNo +
" at " + new Date() + '\n');
// Find the client's host name, and IP address
InetAddress inetAddress = socket.getInetAddress();
ta.appendText("Client " + clientNo + "'s host name is "
+ inetAddress.getHostName() + "\n");
ta.appendText("Client " + clientNo + "'s IP Address is "
+ inetAddress.getHostAddress() + "\n");
});
// Create and start a new thread for the connection
new Thread(new HandleAClient(socket)).start();
}
}
catch(IOException ex) {
System.err.println(ex);
}
}).start();
}
// Define the thread class for handling new connection
class HandleAClient implements Runnable {
private Socket socket; // A connected socket
/** Construct a thread */
public HandleAClient(Socket socket) {
this.socket = socket;
}
/** Run a thread */
public void run() {
try {
// Create data input and output streams
DataInputStream inputFromClient = new DataInputStream(
socket.getInputStream());
DataOutputStream outputToClient = new DataOutputStream(
socket.getOutputStream());
// Continuously serve the client
while (true) {
// Receive radius from the client
double radius = inputFromClient.readDouble();
// Compute area
double area = radius * radius * Math.PI;
// Send area back to the client
outputToClient.writeDouble(area);
Platform.runLater(() -> {
ta.appendText("radius received from client: " +
radius + '\n');
ta.appendText("Area found: " + area + '\n');
});
}
}
catch(IOException e) {
ex.printStackTrace();
}
}
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}