is all in the title :
I create a java client , that sends a message to server when I click a button , several client can connect in same time,here is my source code:
the client:
private void simulerMessageActionPerformed(java.awt.event.ActionEvent evt) {
try {
log.append("wait for connexion..\n");
socket=new Socket(ip.getText(),Integer.parseInt(port.getText()));
log.append("Connexion to the server ok");
BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream()) ); ligne.
PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true);
String str = "test1";
log.append("\n"+str+"\n");
out.println(str);
in.close();
out.close();
socket.close();
} catch (UnknownHostException ex) {
Logger.getLogger(Simulator.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Simulator.class.getName()).log(Level.SEVERE, null, ex);
}
}
the server :
private void demarreActionPerformed(java.awt.event.ActionEvent evt) {
sw=new SwingWorker<String,Void> (){
protected String doInBackground() throws Exception {
try {
server = new ServerSocket(Integer.parseInt(port.getText()));
} catch (IOException ex) {
return "already in use";
}
String str1="waiting for connexion";
String str2="Connexion ok";
log.append(str1+"\n");
PrintWriter out=null;
BufferedReader in=null;
Socket socClient=null;
while(ecoute){
try{
socClient = server.accept();
}catch(java.net.SocketException e){
return "[user] Server Stoped";
}
log.append(str2+"\n");
in = new BufferedReader(
new InputStreamReader(socClient.getInputStream())
);
out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(socClient.getOutputStream())),
true);
String str = in.readLine();
log.append(str+"\n");
}
return "fatal error";
}
protected void done(){
String m="";
try {
m=get();
} catch (InterruptedException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
} catch (ExecutionException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
log.append(m+"\n");
}
};
sw.execute();
}
Currently my server contains a small error when I send a message it works, but after that all the received messages are null...see :
I think the problem comes from that I did not create a thread after socClient = server.accept(); in server ?
if it's the case what would be best ?:
use SwingWorker in a SwingWorker.
create a classic thread with the Runnable interface.
else what is the solution to overcome this problem ?
Thanks ^^.
You probably shouldn't use a SwingWorker in this case. You should have the background processing thread call SwingUtilities.invokeLater() when it's ready to update the GUI. Typically SwingWorker is for things initiated by GUI events, like clicking a button or menu item so that the GUI will not hang and you can get updates into the GUI over time. The important piece is making sure your GUI updates are done on the EDT, and SwingUtilities.invokeLater() will handle that. As alternatives to a basic Thread/Runnable, take a look at Future, Callable, and Executors too, that might give you some ideas how to structure this. SwingWorker uses them internally.
Indeed, you need to create a thread that loops, and each iteration read from the inputstream, something similar to this:
//
thread = new Thread(this);
thread.start();
public void run() {
while(true){
System.out.println("thread is running");
try {
String temp = in.readUTF();
System.out.println(temp);
chattArea.append(temp);
} catch (IOException e) {
}
}
}
If you don't do this, input will be read only once
Related
I am implementing a Transfer Server program which takes messages from clients (via console input) and then forwards it to some sort of mailbox.
To allow concurrent reception of several messages by different clients, I first created a class that implements the Runnable interface. Each of this class instances will handle the communication with exactly one client:
public class ClientConnection implements Runnable {
//...
//...
#Override
public void run() {
try {
// prepare the input reader and output writer
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
Message message = new Message();
String request = "";
// read client requests
while ((request = reader.readLine()) != null) {
System.out.println("Client sent the following request: " + request);
String response;
if (request.trim().equals("quit")) {
writer.println("ok bye");
return;
}
response = message.parseRequest(request);
if (message.isCompleted()) {
messagesQueue.put(message);
message = new Message();
}
writer.println(response);
}
} catch (SocketException e) {
System.out.println("ClientConnection: SocketException while handling socket: " + e.getMessage());
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (InterruptedException e) {
System.out.println("Client Connection was interrupted!");
e.printStackTrace();
} finally {
if (clientSocket != null && !clientSocket.isClosed()) {
try {
clientSocket.close();
} catch (IOException ignored) {}
}
}
}
}
I do have a parent thread which is responsible for starting and managing all the ClientConnection runnables:
#Override
public void run() {
clientConnectionExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
while (true) {
Socket clientSocket;
try {
// wait for a Client to connect
clientSocket = serverSocket.accept();
ClientConnection clientConnection = new ClientConnection(clientSocket, messagesQueue);
clientConnectionExecutor.execute(clientConnection);
} catch (IOException e) {
// when this exception occurs, it means that we want to shut down everything
clientConnectionExecutor.shutdownNow(); // force terminate all ClientConnections
return;
}
}
}
Now according to this Stackoverflow Question, I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run() method, and there, it should print Client Connection was interrupted!. But this does not happen, so the catch clause seems never to be reached, the input reading loop just goes on.
I read in another Stackoverflow question that this might be related to some other codeline within the block seems to be consuming the InterruptedException, but there wasn't any particular information on what codeline could do that. So I am thankful for any hints.
Edit: It turns out that as soon as I manually exit the loop by typing "quit" on the client, the loop will quit and then, Client Connection was interrupted! will be printed. So somehow the exception seems to be ignored as long as the loop is running, and only handled afterwards.
From Oracle docs for shutdownNow:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
If you take a look into ThreadPoolExecutor sources, you will find out that shutdownNow interrupts threads with this code:
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
Your ClientConnection doesn't check the flag Thread.interrupted. Due to information in the post, I can't figure out which method throws InterruptedException. Probably, some other method, for example, readLine of reader or writer, blocks the thread, because they use socket's InputStream and OutputStream and because it's obvious that socket's streams block the thread if data is not immediatly available.
For example, I wrote this code to test it:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress(8080));
Socket socket = serverSocket.accept();
int dataByte = socket.getInputStream().read();
System.out.println(dataByte);
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
}
}
On OpenJdk-16.0.2 there is no actual interruption.
I see two possible solutions for your problem:
Check Thread.interrupted inside the while loop if you are sure that Socket doesn't block your thread.
If your are not sure, use SocketChannel in non-blocking mode instead of Socket for checking Thread.interrupted manually.
For the second way I tranformed my example into this:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocketChannel serverSocket = ServerSocketChannel.open()) {
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(8080));
SocketChannel socket = null;
while (socket == null) {
socket = serverSocket.accept();
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socket.read(byteBuffer);
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.flip();
byteBuffer.get(bytes);
System.out.println(new String(bytes, StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Interrupted successfully");
}
});
thread.start();
thread.interrupt();
}
}
It works.
Good luck with Java :)
I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run()
Your messagesQueue should be a BlockingQueue. So messagesQueue.put(message) will make you need to catch an Interrupted exception. So only when the thread is blocked in the put method(queue is full), you call threadpool#shutdownNow, then the thread will receive an Interrupted exception. In other cases, thread will not receive this Interrupted exception.
You can change while ((request = reader.readLine()) != null) to while ((request = reader.readLine()) != null && !Thread.interrupted()).
Another solution is to maintain all client sockets, and close all client sockets when you need to close them, this way, the client thread will directly receive an IOException:
List<Socket> clientSockets = new ArrayList<>();
while (true) {
try {
Socket accept = serverSocket.accept();
clientSockets.add(accept);
executorService.submit(new ClientConnection(accept));
}catch (Exception e) {
for (Socket socket : clientSockets) {
try {
socket.close();
} catch (Exception exception) {
//
}
}
//executorService.shutdownNow();
}
}
I'm trying to build simple java web server. Every request from a client must be supported by a separate thread. I wrote something like this:
this.serverSocket = new ServerSocket(this.serverPort);
while (!this.isStopped) {
Socket clientSocket = null;
clientSocket = this.serverSocket.accept();
HttpClient client = new HttpClient(clientSocket);
new Thread(client).start();
}
The run() function of HttpClient class:
public void run()
{
try {
InputStream input = client.getInputStream();
OutputStream output = client.getOutputStream();
Thread.sleep(1000);
output.write("HTTP/1.1 200 OK".getBytes());
output.write(("\n\nWorkerRunnable: dd").getBytes());
output.close();
input.close();
} catch (IOException ex) {
Logger.getLogger(HttpClient.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(HttpClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
When I throw away
Thread.sleep(1000);
everything works good, but with this a browser can not connect with the server.
What is the problem?
Try putting Thread.sleep(1000); after the output.write(...) statements. You should acknowledge the client ASAP, then wait.
i have this code to do chatting
but it did not work , but somebody told me that i should use byte array and a string but i did not understand i hope you can help me to fix this problem , this code belongs to the server...
public void run() {
try {
ServerSocket= new ServerSocket(44444);//inside there is the port mumber which will be gain later from firstscreen
ClientSocket= ServerSocket.accept();
OUT= new ObjectOutputStream(ClientSocket.getOutputStream());
IN=new ObjectInputStream(ClientSocket.getInputStream());
while (true){
Object input =IN.readObject();
textArea.setText(textArea.getText()+"Client:"+(String)input+"\n");//update the textarea
}//loop end
}catch (IOException e){
//joptionpane
e.printStackTrace();
} catch (ClassNotFoundException e) {
//joptionpane
e.printStackTrace();
}
}//end of try
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("Send")|| e.getSource() instanceof JTextField){
try {
if(textField.getText().isEmpty()) {
OUT.writeObject(textField.getText());
textArea.setText(textArea.getText()+"Assistant:"+textField.getText()+"\n");}
}
catch (IOException c){
c.printStackTrace();
}
}
I hope you understand that you are only letting just a SINGLE client connect to the server, since there cannot happen any other serverSocket.accept()
First, you are only sending the information if the textfield text is empty at if(textField.getText().isEmpty()) which is quite a nonsense, otherwise there is no call to send through socket any data.
Apart from this, I do not see the code for the actionPerformed block, which I assume you have coded it before with a JButton or so and implementing the jbutton.addActionListener()
Also, I hope ClientSocket is a class of your own, because a client is represented as a Socket, not ClientSocket.
On the other hand, I would suggest the following API writeUTF and forget about needing to cast the string into bytes or otherways, with the help of DataInput and DataOutputStreams.
The code would be left as:
public void run() {
try {
ServerSocket serverSocket= new ServerSocket(44444);//inside there is the port mumber which will be gain later from firstscreen
Socket clientSocket= serverSocket.accept();
DataOutputStream OUT = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream IN = new DataInputStream(clientSocket.getInputStream());
while (true){
String input = IN.readUTF();
textArea.append(input+"\n"); //update the textarea
}//loop end
}catch (IOException e){
//joptionpane
e.printStackTrace();
} catch (ClassNotFoundException e) {
//joptionpane
e.printStackTrace();
}
}//end of try
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("Send")|| e.getSource() instanceof JTextField) {
try {
if(!textField.getText().isEmpty()) { //Do not forget to include the ! (NOT)
OUT.writeUTF(textField.getText());
textArea.setText(textArea.getText()+"Assistant:"+textField.getText()+"\n");
}
}
catch (IOException c){
c.printStackTrace();
}
}
}
I hope to have been able to have helped you.
So, i have a Android-App(Client) and a Java-program(Server), with a One-time socket communication, whenever the android app connects to my server in a special activity (working fine).
Because my server is embedded in a bigger program (with Swing-components, where the server takes its informations from), i have this (reduced) code here:
//somewhere in my Swing-Application
Server myServer = new Server();
myServer.start();
//...
public class Server extends Thread {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(8090);
try {
while (true) {
System.out.println("Server is waiting for connections...");
socket = serverSocket.accept();
startHandler(socket);
}
} finally {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void startHandler(final Socket socket) throws IOException {
System.out.println("Client connected to Server");
Thread thread = new Thread() {
#Override
public void run() {
try {
writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
//doing something usefull, i am sending a JSON-String, which i´ll parse in my app.
writer.write(someStringContainingJSONString);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeSocket();
}
}
private void closeSocket() {
try {
socket.close();
} catch (IOException e) {
}
}
};
thread.start();
}
In my Android-App i have:
public void onCreate(Bundle savedInstanceState) {
viewJSON = new Runnable() {
#Override
public void run() {
getJSON();
}
};
Thread thread = new Thread(null, viewJSON, "MagentoBackground");
thread.start();
myProgressDialog = ProgressDialog.show(myActivity.this, "Please wait...", "Retrieving data ...", true);
}
private void getJSON() {
try {
socket = new Socket(serverIPAddress, SERVER_PORT);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
String help = reader.readLine();
// parse this String according to JSON, is working fine!
}
// catch and so on...
Now, i want the app, to recieve data, whenever i hit a button "send data" from my Swing-Application, to have the newest data available.
On the other hand, i want the server to recieve data (also a JSON-String) when i make changes in my Android app. The String should also be send when i hit a specific button.
How can i do that? The problem is the threading issue(otherwise my swing application wouldn´t work) combined with networking. If i don´t close the socket, i cannot continue with my program properly (or at least, it seems so with my code right now)
Can you help me out here?
Thank you very much in advance for your help and thoughts.
Best, Andrea
I'm trying to write this program which updates itself on the current status of a variable. How I intended it to work is by having a timed task to constantly send the string "update" to the server. The server will recognize the string and will send the necessary values for the variable on the android device. However, I am facing some problems. The string "update" is sending without error but when the corresponding value from the server is sent back, the program does not seem to be able to read the reply. Here is the code:
//Open socket and initialize data streams
try {
socket = new Socket(serverIpAddress, applicationport);
//in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//in = new DataInputStream(socket.getInputStream());
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
} catch (UnknownHostException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
ShowDialog("Login Error" + ex.getMessage());
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
ShowDialog("Login Error" + ex.getMessage());
}
//Create new daemon timer
updateData = new Timer(true);
updateData.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
out.println("update");
UpdateMethod();
}//run
}, 1000, 10000);//schedule the delays start/interval here
};
private void UpdateMethod() {
//This method is called directly by the timer
//and runs in the same thread as the timer.
//It calls the method that will work with the UI
//through the runOnUiThread method.
this.runOnUiThread(Timer_Tick);
};//timermethod
private Runnable Timer_Tick = new Runnable() {
public void run() {
try {
//in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//String getx1 = null;
//getx1 = in.readLine();
//if (getx1 != null) {
//float updatex1 = Float.parseFloat(getx1);
//get_x1 = getx1;
//}
in = new DataInputStream(socket.getInputStream());
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
x1display = (TextView) findViewById(R.id.x1display);
x1display.setText(in.readUTF());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
if (in != null){
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
};
As you can see, I have tried experimenting with both DataInputStream and BufferedReader as well but to no avail.
Edit: It seems that trying to read from the input stream is causing my UI to freeze up. I have no idea what is wrong as my code seems to be without errors..
Any help or advice would be greatly appreciated!
Thank you!
The code looks fine to me. But its not working so looks like you need to chop it up.
Test if the socket stuff is working without the Timer. Make a socket connection and read its response without the Timer and UI code
If that works, introduce the Timer but not the UI code
If that works, do the whole thing (which is failing now)
Somewhere in this test process you should be able to find the culprit
As you have already said, reading blocks the thread. You shouldn't ever read something inside the UI thread! Furthermore, as I remember correctly, closing input before closing output does some nasty things. I would suggest closing the socket instead and putting the BufferedReader back in. This is how it should look like:
//Open socket and initialize data streams
try {
socket = new Socket(serverIpAddress, applicationport);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
} catch (UnknownHostException ex) {
ex.printStackTrace();
ShowDialog("Login Error" + ex.getMessage());
} catch (IOException ex) {
ex.printStackTrace();
ShowDialog("Login Error" + ex.getMessage());
}
//Create new daemon timer
updateData = new Timer(true);
updateData.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
out.println("update");
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
x1display = (TextView) findViewById(R.id.x1display);
x1display.setText(in.readUTF());
} catch (IOException e) {
e.printStackTrace();
}
});
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}}, 1000, 10000);//schedule the delays start/interval here
By the way, don't use printStackTrace(): Why is exception.printStackTrace() considered bad practice?