This question already has answers here:
How do you kill a Thread in Java?
(17 answers)
Closed 9 years ago.
I'm with a headache on killing a thread with java ...
I saw a lot of topics on stackoverflow and i didnt get them working on my code ...
Can someone explain me how am i able to kill a thread without using deprecated function (like stop) and in a safe way please ( also my thread is running a socket: DatagramSocket).
Class p2p_app->
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
//import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class p2p_app {
private String ip;
private Integer porta;
private LinkedList<Vizinho> vizinhos;
private String pathSharedFolder;
private String pathBootStrap;
private int exit;
//private Thread send;
//private Thread receive;
private UDPreceive udpR;
public p2p_app(String args[]) throws IOException {
this.ip = InetAddress.getLocalHost().getHostAddress();
this.vizinhos = new LinkedList<Vizinho>();
this.exit = 0;
//this.send=null;
//this.receive=null;
this.udpR=null;
if(args.length==2){
this.pathSharedFolder=args[0];
this.pathBootStrap=args[1];
System.out.println(pathSharedFolder);
System.out.println(pathBootStrap);
}
else{
this.pathSharedFolder="./";
this.pathBootStrap="./p2p_bootstrap.conf";
System.out.println(pathSharedFolder);
System.out.println(pathBootStrap);
}
readFile(this.pathBootStrap);
createSharedFolder(this.pathSharedFolder);
}
public void assign(String tipo,String info) //tratar o file bootstrap.conf
{
Tipos currentTipos = Tipos.valueOf(tipo.toUpperCase());
switch(currentTipos){
case PATH: if(this.pathSharedFolder==null)
this.pathSharedFolder = info;
break;
case PORTA: this.porta = Integer.parseInt(info);
break;
case IP: StringTokenizer st = new StringTokenizer(info,":");
st.nextElement();
String[] tokens = info.split(":");
Vizinho s = new Vizinho(tokens[0],Integer.parseInt(tokens[1]));
this.vizinhos.add(s);
break;
default:
break;
}
}
public void trataLine(String line){
Pattern p = Pattern.compile("[\\w\\./:]+");
Matcher m = p.matcher(line);
String tipo = "";
while(m.find()){
if(tipo.compareTo("")==0)
tipo = m.group();
else assign(tipo,m.group());
}
}
public void readFile(String path) throws IOException{ //modifiquei este codigo para ver se existe ou nao o ficheiro bootstrap (VASCO)
String line;
Pattern p = Pattern.compile("\\$");
File f = new File(path);
if(f.exists()){
BufferedReader br;
br = new BufferedReader(new FileReader(path));
while ((line = br.readLine()) != null) {
Matcher m = p.matcher(line);
if(m.find() == true)
trataLine(line);
}
br.close();
}
else{
System.out.println("FILE :: BOOTSTRAP.CONF : Doesn't exist.");
}
}
public void createSharedFolder(String path) {
if(!(new File(path).exists()))
new File(path).mkdir();
}
public enum Tipos {
PATH,
PORTA,
T1,
T2,
T3,
R,
M,
K,
IP
}
public String getIp(){
return this.ip;
}
public Integer getPorta(){
return this.porta;
}
public int getExit(){
return this.exit;
}
public void setExit(int exit){
this.exit = exit;
}
public LinkedList<Vizinho> getVizinhos(){
LinkedList<Vizinho> aux = new LinkedList<Vizinho>();
for(Vizinho c : this.vizinhos) aux.add(c);
return aux;
}
public String toString(){
StringBuilder s = new StringBuilder();
s.append("IP:"+this.ip + "\n");
s.append("Porta:"+ this.porta +"\n");
s.append("Directory:" + this.pathSharedFolder + "\n");
s.append("-----Vizinhos-----");
for(Vizinho c : this.vizinhos)
s.append(c.toString());
return s.toString();
}
public void initThreads(p2p_app p2p){
//UDPreceive udpR = new UDPreceive(p2p);
this.udpR = new UDPreceive(p2p);
//UDPsend udpS = new UDPsend(p2p);
//this.receive = new Thread(udpR);
Thread t = new Thread(udpR);
//this.send = new Thread(udpS);
t.start();
//this.receive.start();
//this.send.start();
}
#SuppressWarnings("deprecation")
public void stopThreads(){
this.udpR.stopRun();
//this.receive.interrupt();
//this.receive.stop();
//this.receive.toString();
//this.send.interrupt();
//this.send.toString();
}
public void menu(){
System.out.println("1:Hello");
System.out.println("2:Vasco");
System.out.println("3:Exit");
}
public int choiceMenu(int i){
int numRowsInConsole = 60;
final String ESC = "\033[";
switch(i){
case 1:
System.out.println("FUNCIONOU HELLO");
System.out.print(ESC + "2J");
/*for (int ii=0; ii<numRowsInConsole; ii++) {
// scroll down one line
System.out.println("");
}*/
break;
case 2:
System.out.println("FUNCIONOU VASCO");
System.out.print(ESC + "2J");
break;
case 3:
i=-1;
System.out.print(ESC + "2J");
break;
default:
}
return i;
}
public static void main(String[] args) throws IOException {
int i;
p2p_app p2p = new p2p_app(args);
//p2p.initThreads(p2p);
System.out.println(p2p.toString());
Scanner sc = new Scanner(System.in);
while(p2p.getExit() != -1){
p2p.menu();
i = sc.nextInt();
p2p.setExit(p2p.choiceMenu(i));
System.out.println(p2p.getExit());
}
System.out.println("Woot woot!");
//p2p.stopThreads();
}
}
Classe UDPreceive->
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPreceive implements Runnable {
private p2p_app p2p;
private DatagramPacket p;
public volatile boolean stopThread = true;
public void stopRun(){
this.stopThread=false;
}
public UDPreceive(p2p_app p2p){
this.p2p = p2p;
}
/**
* #param args
*/
public void run(){
DatagramSocket socket=null;
UDPpacket udp;
byte[] x = new byte[1000];
try{
socket = new DatagramSocket(8734);
socket.setBroadcast(true);
//while(this.p2p.getExit() !=-1){
while(stopThread){
p = new DatagramPacket(x,x.length);
socket.receive(p);
udp = new UDPpacket(p,this.p2p);
udp.tostring();
//udp.setDatagramPacket(p);
//String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
}
//Thread.sleep(100);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
how am i able to kill a thread on my main function in p2p_app class ? i create a thread for my UDPreceiver class :F
For the most part, the only "safe" way to kill a Thread is to code the Thread in such a way that it can receive a signal to stop. For example, use a boolean variable called shouldQuit and have the Thread periodically check that variable, quitting if it's true. You could also do stuff like interrupt the Thread, but that isn't always safe.
package test;
/**
* simple thread class that prints '.' to the screen
* #author Manex
*
*/
public class ThreadTest extends Thread {
private boolean running = true ;
public void run(){
try{
while(running){
//do something here
System.out.print(".");
sleep(1000);
}
}catch(InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("Stopped");
}
/**
* a method to stop the thread
*/
public void stopRunning(){
this.running = false ;
}
public static void main(String[] args){
//creating threads
ThreadTest[] t = new ThreadTest[2] ;
t[0] = new ThreadTest() ;
t[1] = new ThreadTest() ;
//starting threads
for(ThreadTest e : t){
e.start();
}
try {
//the main thread does something
int x = 5 ;
while(x > 0){
sleep(1000) ;
x -= 1 ;
}
//the main thread ended
System.out.println("main thread ends here");
} catch (InterruptedException e) {
e.printStackTrace();
}
//before exiting - stop all threads
for(ThreadTest e : t){
e.stopRunning();
}
}
}
if ur planing on stopping threads that you have created , for any reason , you should keep tracking them and hold a reference to each thread you might want to stop instead of waiting for it to done execution all by itself (the run method simply ends).
in this simple test , if you remove the stop loop , the threads will continue printing and never stop untill you stop them manually , even after main thread termination..
i hope this was usefull..
The reason your UDPReceive thread is not stopping is you are using the blocking method DatagramSocket.receive() in your UDPReceive.run() while loop. The JavaDocs for this method say: "This method blocks until a datagram is received." By blocks it means never, ever returns. So the thread with the receive() is still running when you want your program to exit. It is a "hung thread" and the only way to relieve it is to kill the entire process, such as Ctrl+C.
To fix it, call socket.setSoTimeout() before your UDPReceive.run() while loop starts. This will make the final call to receive() timeout and actually complete. Then catch the SocketTimeoutException that will occur if your socket times out (e.g. at the end of your program when the thread completes, or earlier if you have an actual timeout error condition) and handle the exception appropriately (e.g. if stopThread is triggered just ignore the exception, or if stopThread is not yet triggered log it as a warning). Example:
public void run(){
DatagramSocket socket=null;
UDPpacket udp;
byte[] x = new byte[1000];
try{
socket = new DatagramSocket(8734);
socket.setBroadcast(true);
socket.setSoTimeout(20*1000); // 20 seconds
//while(this.p2p.getExit() !=-1){
while(stopThread){
p = new DatagramPacket(x,x.length);
try {
socket.receive(p);
} catch (SocketTimeoutException e) {
if (stopThread){
System.err.println("Warning: socket timed out " +
"before program completed: " + e.getLocalizedMessage());
} else {
// program completed, so just ignore and move on
break;
}
}
udp = new UDPpacket(p,this.p2p);
udp.tostring();
//udp.setDatagramPacket(p);
//String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
}
//Thread.sleep(100);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This should do the trick. The stopThread logic itself looks fine (although I would rename the boolean to continueThread, because you're stopping when it is false).
Finally , i did it !
The result was a little different from what you guys said,
I'll post my answer in case if anyone will ask it !
The solution was to send a DatagramPacket to myself ! :)
Class udpReceiver ->
//package testeThread;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
public class udpReceiver implements Runnable {
public volatile boolean stopThread = true;
private DatagramSocket socket;
//private DatagramSocket socket;
public udpReceiver() {
// TODO Auto-generated constructor stub
//this.socket = socket;
}
public void stopRun(){
synchronized(this){
this.stopThread=false;
byte[] x = new byte[1000];
try{
DatagramPacket p = new DatagramPacket(x,x.length,InetAddress.getLocalHost(),8737);
this.socket.send(p);
} catch(UnknownHostException e){
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}
}
}
/**
* #param args
*/
public void run(){
//DatagramSocket socket=null;
DatagramPacket p = null;
//byte[] x = new byte[1000];
try{
this.socket = new DatagramSocket(8737);
this.socket.setBroadcast(true);
}catch(SocketException e){
e.printStackTrace();
}
//socket.setSoTimeout(5*1000); // 20 seconds
while(stopThread){
byte[] x = new byte[1000];
p = new DatagramPacket(x,x.length);
try{
this.socket.receive(p);
}catch(IOException e){
e.printStackTrace();
}
String d = new String(p.getData());
System.out.println("Mensagem enviada por mim: "+d);
}
this.socket.close();
/* try{
socket = new DatagramSocket(8735);
socket.setBroadcast(true);
//socket.setSoTimeout(5*1000); // 20 seconds
while(stopThread){
byte[] x = new byte[1000];
p = new DatagramPacket(x,x.length);
try {
socket.receive(p);
} catch (SocketTimeoutException e) {
if (stopThread){
//System.err.println("Warning: socket timed out before program completed: " + e.getLocalizedMessage());
} else {
// program completed, so just ignore and move on
break;
}
}
String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
//System.out.println("SOCKET CLOSE"+socket.isConnected());
}
//socket.setSoTimeout(1000);
socket.close();
System.out.println("SOCKET CLOSE"+socket.isConnected());
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException io){
io.printStackTrace();
}*/
/*catch (SocketTimeoutException soc){
if(this.stopThread == false) {
this.stopThread = false;
}
soc.printStackTrace();
}*/
}
}
Class Servidor->
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Scanner;
//package testeThread;
public class Servidor {
private int exit;
public Servidor() {
// TODO Auto-generated constructor stub
}
public int getExit(){
return this.exit;
}
public void setExit(int exit){
this.exit = exit;
}
public int choiceMenu(int i){
int numRowsInConsole = 60;
final String ESC = "\033[";
switch(i){
case 1:
System.out.println("FUNCIONOU HELLO");
System.out.print(ESC + "2J");
/*for (int ii=0; ii<numRowsInConsole; ii++) {
// scroll down one line
System.out.println("");
}*/
break;
case 2:
System.out.println("FUNCIONOU VASCO");
System.out.print(ESC + "2J");
break;
case 3:
i=-1;
System.out.print(ESC + "2J");
break;
default:
}
return i;
}
public void menu(){
System.out.println("1:Hello");
System.out.println("2:");
System.out.println("3:Exit");
}
#SuppressWarnings("deprecation")
public static void main(String[] args) {
int i;
Servidor s = new Servidor();
//try{
//DatagramSocket socket = new DatagramSocket(8735);
udpReceiver udpR = new udpReceiver();
Thread t = new Thread(udpR);
t.start();
Scanner sc = new Scanner(System.in);
while(s.getExit() != -1){
s.menu();
i = sc.nextInt();
s.setExit(s.choiceMenu(i));
System.out.println(s.getExit());
}
//DatagramSocket socket = new DatagramSocket(8735);
//socket.close();
//t.interrupt();
udpR.stopRun();
try{
t.join();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("MAIN FIM");
//t.stop();
/*}catch(SocketException e){
e.printStackTrace();
}*/
}
}
P.S: that version isn't the same as the one upstairs ... But i get the same logic as i wrote the other one , and now it works good ! I can quit the program without using CTRL+C and it can receives the message now ! :)
Related
I have this Server class,
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
public static ArrayList<String> waiting = new ArrayList<String>();
public static ArrayList<String> playing = new ArrayList<String>();
public static ArrayList<Integer> score = new ArrayList<Integer>();
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(4321);
while (true) {
try {
Socket socket = server.accept();
new EchoThread(socket).start();
} catch (Exception exc) {
exc.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void addClient(String name) {
waiting.add(name);
}
public int getNumClients() {
return waiting.size();
}
public String getClientName(int i) {
return waiting.get(i);
}
public void play() {
int scr = 0;
for (int i = 0; i < 4; i++) {
playing.add(waiting.get(0));
score.add(scr);
waiting.remove(0);
}
}
public boolean checkIfPlaying(String name) {
if (playing.indexOf(name) >= 0) {
return true;
} else {
return false;
}
}
}
and the Thread Class,
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoThread extends Thread {
protected Socket socket;
public EchoThread(Socket clientSocket) {
this.socket = clientSocket;
}
public void run() {
Server s = new Server();
DataInputStream in = null;
DataOutputStream out = null;
String line;
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
while (true) {
try {
line = in.readLine();
String[] prot = line.split(":");
if (prot[0].equals("/login")) {
s.addClient(prot[1]);
} else if (prot[0].equals("/waiting")) {
if (s.checkIfPlaying(prot[1])) {
out.writeBytes("Playing" + "\r\n");
} else {
if (s.getNumClients() >= 4) {
s.play();
out.writeBytes("Playing" + "\r\n");
} else {
out.writeBytes(s.getNumClients() + "\r\n");
}
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
If the client connect to the server, the name of the client is stored in Server Class Array, waiting.
If the waiting clients is equals to 4, it will remove from the waiting array and put it in playing array.
I would like to make the server send message to the first 4 clients in playing array.
How can I do it?
For your Server Class, I would change your ArrayList< String > for waiting and playing to ArrayList< EchoThread >. This way your Server class is tracking each client object themselves instead of just their names. When you instantiate your EchoThread objects, I would pass the local server object to each EchoThread that way each object knows about the server that instantiated them.
Server Class
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
public ArrayList<EchoThread> waiting = new ArrayList<EchoThread>();
public ArrayList<EchoThread> playing = new ArrayList<EchoThread>();
public ArrayList<Integer> score = new ArrayList<Integer>();
public static void main(String[] args) {
try {
// Instantiate a single server object that you can pass into your connected clients
Server myServer = new Server();
ServerSocket server = new ServerSocket(4321);
while (true) {
try {
Socket socket = server.accept();
// Pass myServer into Echo Thread
new EchoThread(myServer, socket).start();
} catch (Exception exc) {
exc.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Have to synchronize this since multiple clients could be adding to this list at the same time
public synchronized void addClient(EchoThread client) {
waiting.add(client);
}
public int getNumClients() {
return waiting.size();
}
public String getClientName(int i) {
return waiting.get(i).getCName();
}
public void play() {
int scr = 0;
for (int i = 0; i < 4; i++) {
EchoThread clientBeingMovedToPlaying = waiting.get(0);
playing.add(clientBeingMovedToPlaying);
score.add(scr);
waiting.remove(0);
// This will be a new method in your EchoThread class
clientBeingMovedToPlaying.SendServerPlayingMessage();
}
}
public boolean checkIfPlaying(String name) {
boolean isPlaying = false;
for(EchoThread client : playing) {
if (client.getName().contentEquals(name)) {
isPlaying = true;
break;
}
}
return isPlaying;
}
}
For your Echo Thread class, I would make your variables in your run method class variables so they can be used throughout the class
EchoThread Class
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoThread extends Thread {
protected Socket socket;
protected Server s;
protected DataInputStream in;
protected DataOutputStream out;
protected String line;
protected String clientName;
// This way, each EchoThread object knows about the server
public EchoThread(Server theServer, Socket clientSocket) {
this.s = theServer;
this.socket = clientSocket;
}
public void run() {
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
while (true) {
try {
line = in.readLine();
String[] prot = line.split(":");
if (prot[0].equals("/login")) {
// Original code
//s.addClient(prot[1]);
// New code
clientName = prot[1];
s.addClient(this);
} else if (prot[0].equals("/waiting")) {
if (s.checkIfPlaying(prot[1])) {
out.writeBytes("Playing" + "\r\n");
} else {
// You don't want multiple clients firing the play method, so you need to synchronize your server object
synchronized (s) {
if (s.getNumClients() >= 4) {
s.play();
out.writeBytes("Playing" + "\r\n");
} else {
out.writeBytes(s.getNumClients() + "\r\n");
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
public String getCName() {
return clientName;
}
public void SendServerPlayingMessage() {
if (out != null) {
// Send whatever message you want
}
}
}
I think this'll get you what your wanting... Forgive any syntax or logical errors, I don't have an IDE right in front of me at the moment.
I have problem with my multhreaded server for bridge auction. The topic of it is less important, all I need to do so far is to make the loop inside the run method work for more than only one "lap". I mean my loop is working for each client only once and then It stopped, but I can't solve this problem. It should work all the time and after sequence of players N-> E-> S-> W-> it start another lap from player N, but now it just stand still...
Check my code:
package serwer;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.*;
public class Serwer {
public static void main(String[] args) throws Exception {
System.out.println("Started server to the bridge auction");
int conCount = 0;
ServerSocket serwer = new ServerSocket(9898);
ArrayList<connection> connections = new ArrayList<connection>(){};
try {
//only 4 players are allowed to play bridge in one table
while (connections.size() < 4) {
connection p = new connection(serwer.accept(), conCount++);
connections.add(p);
connections.get(conCount-1).start();
}
} finally {
serwer.close();
}
}
/**
* static class responsible for the connection in multithreaded server
*/
static class connection extends Thread {
private Socket socket;
private int conCount;
private static int counter = 0;
private final String[] Players;
private String stringOnServer = "0";
private int stake = 1;
public connection(Socket socket, int conCount) {
this.Players = new String[]{"N", "E", "S", "W"};
this.socket = socket;
this.conCount = conCount;
System.out.println("New connection id: " + Players[conCount]);
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
//here is info what player are you
out.println("You are player on position " + Players[conCount]);
while (true) {
synchronized (this) {
if (counter % 4 == conCount) {
while (true) {
out.println("Your turn " + Players[conCount] + ", please input the text: ");
String input = in.readLine();
System.out.println("\t" + Players[conCount] + " : " + input);
counter += 1;
//for now only the stringOnServer is simply echo
stringOnServer = input;
System.out.println("\tCurrent string on server = " + stringOnServer);
try {
this.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Serwer.class.getName()).log(Level.SEVERE, null, ex);
}
break;
}
} else {
this.notify();
}
}
}
} catch (IOException e) {
System.out.println("error with player: " + Players[conCount] + ": " + e);
} finally {
try {
socket.close();
} catch (IOException e) {
System.out.println("can't closed");
}
System.out.println("connection with player" + Players[conCount] + " terminated");
}
}
}
}
Client's code is really simple, but if someone will have time and patience to test it I add it to:
package klient;
import java.net.*;
import java.io.*;
public class Klient {
public static void main(String[] args) throws IOException {
try {
Socket s = new Socket("127.0.0.1", 9898);
String answer;
System.out.println("Welcome on the server of auction.");
//Here is displayed info from server what player are you
BufferedReader fromServer = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println(fromServer.readLine());
while (true) {
System.out.println(fromServer.readLine());
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
answer = input.readLine();
out.println(answer);
}
} catch (ConnectException ex) {
System.out.println("There are 4 players on server or server is closed, try again later");
}
}
}
The problem is in this loop in connection class with counter.
Thanks in advance for your help :)
You have to call notify() from another thread. Your current thread is waiting and cannot notify itself.
I'm trying to figure out a way to get an instance of a server to negotiate between two clients by creating a chat thread between them.
I created this project, and it "almost" works... but it seems like there is a buffer of synch problem.
when writing a line in one side (i.e Client#1), it doesn't pass to the other side (i.e Client#2), but only after Client#2 trys to pass a line too.
I know there might be better ways to implement this, but I'd like to understand what's wrong with my code.
your help would be great!
the code:
server
import java.io.*;
import java.net.*;
public class Server
{
public static void main(String[] args)
{
int id = 1;
System.out.println();
System.out.println("Server");
try
{
ServerSocket serverSocket = new ServerSocket(4321);
while (true)
{
Socket client1Socket = serverSocket.accept();
Socket client2Socket = serverSocket.accept();
System.out.println("clients connected from ports: \n"
+ client1Socket.getPort() + ", " + client2Socket.getPort());
Thread client1Thread = new ServerThread(client1Socket, client2Socket, id);
client1Thread.start();
id++;
Thread client2Thread = new ServerThread(client2Socket, client1Socket, id);
client2Thread.start();
id++;
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
server thread
import java.io.*;
import java.net.*;
import java.util.*;
public class ServerThread extends Thread
{
Socket sourceSocket;
Socket destSocket;
int id;
public ServerThread(Socket src, Socket dst, int n)
{
sourceSocket = src;
destSocket = dst;
id = n;
}
public void run()
{
try
{
Scanner clientInput = new Scanner(sourceSocket.getInputStream());
PrintStream destOutput = new PrintStream(destSocket.getOutputStream());
destOutput.println("You are chatting with Client " + id);
boolean more = true;
while (more)
{
String input = clientInput.nextLine();
destOutput.println(input);
if (input.equals("Q"))
{
more = false;
}
}
sourceSocket.close();
destSocket.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
client
import java.io.*;
import java.net.*;
import java.util.*;
public class Client
{
public static void main(String[] args)
{
System.out.println();
System.out.println("Client");
try
{
Socket clientSocket = new Socket("localhost", 4321);
System.out.println("Connection Established");
Scanner input = new Scanner(clientSocket.getInputStream());
PrintStream output = new PrintStream(clientSocket.getOutputStream());
Scanner in = new Scanner(System.in);
System.out.println(input.nextLine());
boolean more = true;
while (more)
{
String text = in.nextLine();
output.println(text);
String nextInput = input.nextLine();
if (nextInput == null)
{
more = false;
}
else
{
System.out.println(nextInput);
}
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
In your client code, the line String text = in.nextLine(); will block your thread. That means if you never type in anything in your client, you can not receive anything. So the solution is to put your message receiving code in another thread. such as:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (!Thread.interrupted()) {
System.out.println(input.nextLine());
}
}
});
thread.start();
while (true)
{
String text = in.nextLine();
output.println(text);
// String nextInput = input.nextLine();
......................
}
I have developed a code which for multiple host and port connection using socket to return the status of the list of hosts. Problem is it is taking 5 mins to ping and return the status for only 10 connections. Any ideas why it takes so long?
import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.PortUnreachableException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestIPList {
private static final Logger logger = LoggerFactory.getLogger(TestIPList.class);
static ArrayList<String> ipList = new ArrayList<String>();
public static ArrayList<String> captureValues() throws IOException,ConnectException
{
//Pattern ptn = Pattern.compile("(\\d{1,3})\\.(\\d{1,3})\\.
(\\d{1,3})\\.(\\d{1,3})");
Scanner ipFile = null;
String iList="";
ArrayList<String> ips = new ArrayList<String>();
ArrayList<String> returnList = new ArrayList<String>();
/*read the file at local path */
try {
ipFile = new Scanner (new File ("c:\\list.txt"));
}
catch(IOException e){
logger.debug( "[-] Cant open the file!");
System.exit(0);
}
/*Iterate thru the file */
while(ipFile.hasNext()){
ips.add(ipFile.next());
}
String[] ipPort;
for(int i=0;i<ips.size();i++){
iList = ips.get(i);
ipPort= iList.split(":");
Socket ss = null;
boolean status = false;
try {
/*Socket class.. here it is taking time to ping*/
ss = new Socket(ipPort[0], Integer.parseInt(ipPort[1]));
status = true; //there is a listening port
ss.close();
}
catch (IOException e) {
//e.printStackTrace();
}
finally {
if (ss != null) {
try {
ss.close();
}
catch(PortUnreachableException e)
{
ss=null;
System.err.println("Got an "+e);
}
catch (UnknownHostException e) {
// TODO Auto-generated catch block
ss=null;
System.err.println("Got an "+e);
}
catch (IOException e) {
ss=null;
}
}
}
/*return status*/
if(status==true){
returnList.add("true");
}
else{
returnList.add("false");
}
}
/* return list of status*/
return returnList;
}
/*static method*/
public static void main(String a[]) throws IOException,ConnectException {
/* Into the main method */
ArrayList<String> ipexists = new ArrayList<String>();
ipexists =captureValues();
System.out.println("ArrayList Status---------"+captureValues());
/*End of the program*/
}
}
You might want to try specifying a timeout:
SocketAddress sa = new InetSocketAddress(ipPort[0], Integer.parseInt(ipPort[1]));
Socket ss = new Socket();
int timeoutMillis = 500;
ss.connect(sa, timeoutMillis);
Edit: In order to do the same with multiple threads you could modify the code like this:
final ArrayList<String> ips = new ArrayList<String>();
// ..
final List<String> returnList = Collections.synchronizedList(new ArrayList<String>(ips));
Collections.fill(returnList, "false");
int nThreads = 10;
final ExecutorService es = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < ips.size(); i++) {
final int index = i; // needs to be final to be available in local class
es.execute(new Runnable() {
#Override
public void run() {
String iList = ips.get(index);
String[] ipPort = iList.split(":");
final String host = ipPort[0];
final int port = Integer.parseInt(ipPort[1]);
Socket ss = null;
boolean status = false;
try {
int timeoutMillis = 1500;
InetAddress ia = InetAddress.getByName(host);
// Edit: isReachable often fails for public sites
//if (!ia.isReachable(timeoutMillis))
// throw new UnknownHostException(host);
SocketAddress sa = new InetSocketAddress(ia, port);
ss = new Socket();
ss.connect(sa, timeoutMillis);
status = true;
ss.close();
} catch (IOException e) {
// e.printStackTrace();
} finally {
if (ss != null) {
try {
ss.close();
} catch (PortUnreachableException e) {
ss = null;
System.err.println("Got an " + e);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
ss = null;
System.err.println("Got an " + e);
} catch (IOException e) {
ss = null;
}
}
}
/* return status */
if (status == true) {
returnList.set(index, "true");
} else {
returnList.set(index, "false");
}
}
});
}
es.shutdown();
es.awaitTermination(60, TimeUnit.SECONDS);
List<Runnable> pending = es.shutdownNow();
if (!pending.isEmpty()) System.err.println("Pending threads: " + pending);
For an alternative multi-threaded, more complex example you may want to have a look at Ping.java of Oracles NIO and NIO.2 Examples.
Edit: Commented out the isReachable branch because it does rarely work with public websites.
Before people suspect that I have no idea what I'm doing at all (and end up voting this down for no reason at all), please read this:
It connects to my server just fine! I'm getting no errors (from the client OR server), and my server is recognizing the connection. It works with my friend's client that he made, but I wanted to make my own client, and apparently I'm doing something wrong. PLEASE STAY ON TOPIC! Thanks :)
Title basically says it all. I've tested with println messages above and below the setupStream() in my Client.java run(), but only the message above the setupStream() prints. I'm not sure how I'm supposed to initialize my stream without making my program come to a halt.
Client.java
import java.io.IOException;
public class Client extends Stream implements Runnable {
public boolean running = false;
private Thread clientThread;
Frame frame;
public Client() {
super("localhost", 43594);
frame = new ClientFrame(500, 500);
start();
}
public synchronized void start() {
if(running) return;
running = true;
clientThread = new Thread(this);
clientThread.start();
}
public synchronized void stop() {
if(!running) return;
running = false;
clientThread.interrupt();
try {
clientThread.join();
} catch (InterruptedException e) {e.printStackTrace();}
}
public void run() {
try{
setupStream();
while(running) {
System.out.println("running");
}
}catch(IOException e) {
e.printStackTrace();
}finally {
try{
out.close();
in.close();
socket.close();
clientThread.join();
}catch(IOException | InterruptedException e) { e.printStackTrace(); }
}
}
public static void main(String[] args) {
new Client();
}
}
Stream.java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Stream {
Socket socket;
ObjectOutputStream out;
ObjectInputStream in;
String data;
public Stream(String host, int port) {
try {
socket = new Socket(host, port);
} catch (IOException e) {
e.printStackTrace();
}
}
protected void setupStream() throws IOException {
out = new ObjectOutputStream(socket.getOutputStream());
out.flush();
in = new ObjectInputStream(socket.getInputStream());
}
}
My Server Thread:
package Server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
public class User extends Thread {
public static int users = 0;
public int ID;
public String username;
boolean online = false;
public static ArrayList<String> usernames = new ArrayList<String>();
Socket socket;
DataOutputStream out;
DataInputStream in;
String input;
public User(Socket socket) {
this.socket = socket;
}
public String decode(String input) {
String[] split = input.split(" ");
if(input.startsWith("::")) {
try {
switch(split[0].substring(2, split[0].length()).toLowerCase()) {
case "setname":
case "changename":
case "newname":
if(usernames.contains(split[1].toLowerCase())) {
out.writeUTF("This name is already taken! Please choose a different one.");
out.flush();
return null;
}
if(username == null) {
username = split[1].substring(0, 1).toUpperCase() + split[1].substring(1, split[1].length());
Server.users.put(split[1].toLowerCase(), Server.user[ID]);
usernames.add(split[1].toLowerCase());
} else {
usernames.remove(username.toLowerCase());
username = split[1].substring(0, 1).toUpperCase() + split[1].substring(1, split[1].length());
usernames.add(split[1].toLowerCase());
}
return null;
case "rank+":
return null;
case "[sm]=":
return null;
}
}catch(IOException e) { }
}
return input;
}
String timeStamp;
public void run() {
try {
out = new DataOutputStream(socket.getOutputStream());
out.flush();
in = new DataInputStream(socket.getInputStream());
while((input = in.readUTF()) != null) {
input = decode(input);
if(input != null) {
if(username != null) {
timeStamp = new SimpleDateFormat("[h:mm:ss] ").format(Calendar.getInstance().getTime());
Server.sendGlobalMessage(timeStamp + username +": "+input);
} else {
timeStamp = new SimpleDateFormat("[h:mm:ss] ").format(Calendar.getInstance().getTime());
Server.sendGlobalMessage(timeStamp + "Guest "+ID+": "+input);
}
}
}
}catch(IOException e) { e.printStackTrace(); } finally {
try{
out.close();
in.close();
socket.close();
} catch(IOException e) { e.printStackTrace(); }
}
}
}
I haven't touched the code of my Server Thread for a while, since it has always worked up until I made my new client.
I suspect that your server does not create an ObjectOutputStream, so when the client constructs its ObjectInputStream, it blocks waiting for the object stream header, which never arrives.