UPDATE: Thank you very Antoniossss and Peter Lawrey!
I created a Multi-Threaded Server - Client Communication.
I have 3 Classes: Server, Client, RequestHandler.
The server opens a ServerSocket and then starts to listen for clients via accept() and if a client connects, he refers the client's task(some String) to the RequestHandler.
The command important to me is "SHUTDOWN".
If the RequestHandler finds this command, he calls a method within the Server to shutdown.
This method is based on the usage Example of the Executor Service:
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html (if you do not want to click on the link, see the FAT text for the method)
You do not have to read the code provided below, but in case someone is interested in it I am providing it
The method of the usage Example:
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
public class MulServer_v1 {
protected static int portNumber = 8540;
protected static int max_Clients = 3;
protected static boolean shutdownFlag = false;
private static ServerSocket serverSocket;
protected ExecutorService executor;
protected static ArrayList<Socket> socketList = new ArrayList<>();
public MulServer_v1(int portNumber, int poolSize) {
}
public void runServer() {
try {
serverSocket = new ServerSocket(portNumber);
executor = Executors.newFixedThreadPool(max_Clients);
} catch (IOException e) {
System.out.println("Could not create server on specific port");
e.printStackTrace();
}
while (!shutdownFlag) {
try {
Socket clientSocket = serverSocket.accept();
socketList.add(clientSocket);
executor.submit(new RequestHandler_v1(clientSocket));
} catch (IOException e) {
System.out.println("Couldn't accept on the Socket");
executor.shutdown();
e.printStackTrace();
}
}
shutdownAndAwaitTermination();
}
public void shutdownAndAwaitTermination() {
System.out.println("Shutting down..");
executor.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
executor.shutdownNow();
// Cancel currently executing tasks
System.out.println("komme ich hierhin?");
// Wait a while for tasks to respond to being cancelled
if (!executor.awaitTermination(10, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
executor.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
try {
serverSocket.close();
} catch (IOException e) {
System.out.println("Serversocket konnte nicht geschlossen werden");
e.printStackTrace();
}
System.out.println("I got here!");
for (Socket s : socketList) {
if (s != null) {
try {
s.close();
} catch (IOException e) {
System.out.println("Couldn't close the socket");
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
MulServer_v1 server = new MulServer_v1(portNumber, max_Clients);
server.runServer();
}
}
public class Client_v1 {
public static final String HOSTNAME = "localhost";
public static final int PORTNUMBER = 8540;
private static boolean clientClose = false;
public static void main(String[] args) throws IOException {
System.out.println("Client started");
try (Socket socket = new Socket(HOSTNAME, PORTNUMBER);
PrintWriter out = new PrintWriter(socket.getOutputStream(),
true);
// InputStream test = echoSocket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in))) {
String userInput;
while ((userInput = stdIn.readLine()) != null && !clientClose) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
// if (userInput.equals("BYE")) {
// break;
// }
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + HOSTNAME);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to "
+ HOSTNAME);
System.exit(1);
}
}
protected static void closeClient() {
clientClose = true;
}
}
public class RequestHandler_v1 implements Runnable {
// private final String password = "passwort";
private final Socket client;
private boolean closeFlag = false;
public RequestHandler_v1(Socket client) {
this.client = client;
}
#Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(client.getOutputStream()));) {
System.out.println("Thread started with name:"
+ Thread.currentThread().getName());
String userInput;
String serverResponse;
while ((userInput = in.readLine()) != null) {
serverResponse = processInput(userInput);
System.out.println("Received message from "
+ Thread.currentThread().getName() + " : " + userInput);
writer.write("Sever Response : " + serverResponse);
writer.newLine();
writer.flush();
if (closeFlag) {
Client_v1.closeClient();
MulServer_v1.socketList.remove(client);
client.close();
}
}
} catch (IOException e) {
System.out.println("I/O exception: " + e);
} catch (Exception ex) {
System.out.println("Exception in Thread Run. Exception : " + ex);
}
}
public String processInput(String input) {
boolean commandFound = false;
String output = "";
try {
if (input.getBytes("UTF-8").length > 255)
output = "Max string length exceeded";
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Pattern allPattern = Pattern
.compile("(?<lower>^LOWERCASE\\s.+)|(?<upper>^UPPERCASE\\s.+)|(?<reverse>^REVERSE\\s.+)|(?<bye>^BYE)|(?<shutdown>^SHUTDOWN passwort)");
Matcher allMatcher = allPattern.matcher(input);
if (allMatcher.find()) {
String lower = allMatcher.group("lower");
String upper = allMatcher.group("upper");
String reverse = allMatcher.group("reverse");
String bye = allMatcher.group("bye");
String shutdown = allMatcher.group("shutdown");
commandFound = true;
if (lower != null) {
output = lower.substring(10).toLowerCase();
}
if (upper != null) {
output = upper.substring(10).toUpperCase();
}
if (reverse != null) {
output = new StringBuilder(reverse.substring(8)).reverse()
.toString();
}
if (bye != null) {
output = "BYE";
closeFlag = true;
}
if (shutdown != null) {
output = "SHUTDOWN";
MulServer_v1.shutdownFlag = true;
closeFlag = true;
}
} else {
commandFound = false;
output = "UNKNOWN COMMAND";
}
if (commandFound) {
output = "OK ".concat(output);
} else {
output = "ERROR ".concat(output);
}
return output;
}
}
Now the shutting down works, but new clients can connect after the shutdown. How is that possible?
This is Sysout I used to check:
Shutting down..
Thread started with name:pool-1-thread-3
Received message from pool-1-thread-3 : . //<--This (Sending a message) should //NOT be able to happen, since executor.shutdown(); has already been called.
The thing is that your signaling is broken:
while (!shutdownFlag) {
try {
Socket clientSocket = serverSocket.accept();
executor.execute(new RequestHandler_v1(clientSocket));
} catch (IOException e) {
accept() is blocking operation - it blocks until new connection comes right? And here is the culrpit. After you send your "shutdown" command, current thread will unblock, submit the tast, pass the while condition and block again on accept(). After this, proper executor will set the flag to false, but server is still accepting so pool is never shut down.
Another attempt to connect should wake the server and honor shutdownFlag breaking out of the loop and causing all handlers to die after 10 seconds.
Also:
while ((userInput = in.readLine()) != null) {
is a blocking operation - it block your tasks from finishing thus pool will newer shut down. null will be returned if stream will end - either naturally or by an exception. You are not ending the stream on neither of sides. So it will block.
ExecutorsService#shutdownNow() does not mean that threads from pool will be killed - they are signalled to terminate, and threads are to gracefully terminate just like #PeterLawrey mentioned, using Thread.isTerminated() flag.
Proof of concept that closing the socket will break from blocked IO operation:
public class Buffers {
private static Socket client;
static class ServerThread extends Thread {
#Override
public void run() {
try {
ServerSocket serverS = new ServerSocket(1099);
client = serverS.accept();
client.getOutputStream().write('a');
client.getOutputStream().flush();
Thread.sleep(2000);
client.close();
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
static class ClientThread extends Thread {
#Override
public void run() {
try {
Thread.sleep(500);
Socket socket = new Socket("127.0.0.1", 1099);
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("Will try to read");
String line=null;
while ((line = input.readLine()) != null) { // block here
System.out.println("Read " + line); // will never come here
}
} catch (Exception e) {
System.out.println("Server closed the connection!");
}
super.run();
}
}
public static void main(String[] args) throws InterruptedException {
new ServerThread().start();
ClientThread t = new ClientThread();
t.start();
t.join();
}
If you comment client.close(); app will never end just like in your case.
Related
I have a multithreaded tcp server, that handles multiple clients.
Each client has its thread on the serverside that keeps the socket connection.
Everything theoretically works fine for many minutes, but at rare occasions, while having multiple clients connected, the following happens:
One of the clients sends a tcp packet to the server and the serverside read times out. I have found many questions, that tackle read timeouts on the clientside, but in my case, this never happens. In my case, the server times out on a read when receiving a packet from a client.
My question is, why and how can this happen and what can I do to handle this problem?
here is my server listener:
public class GameServerTCP extends Thread {
//TCP
private ServerSocket serverSocket;
public Server server;
public int amountOfTCPConnections = 0;
ClassLoader classLoader = getClass().getClassLoader();
File myFile = new File(classLoader.getResource("Sprites/sprite_sheet.png").getFile());
public GameServerTCP(Server game) {
this.server = game;
//TCP
try {
serverSocket = new ServerSocket(6336);
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(true) {
//TCP
Socket socket = null;
try {
socket = serverSocket.accept();
Toolkit.getDefaultToolkit().beep();
System.out.println(socket.getRemoteSocketAddress() + " has connected to server.");
}
catch (Exception e) {
e.printStackTrace();
}
new TCPConnection(socket, this);
amountOfTCPConnections++;
if (amountOfTCPConnections > 500) {
System.err.println("Too many clients error! (unsolved)");
server.frame.dispatchEvent(new WindowEvent(server.frame, WindowEvent.WINDOW_CLOSING));
}
}
}
}
here is my server thread that hold each single connection:
public class TCPConnection implements Runnable {
Socket socket;
private Thread thread;
private boolean isRunning = false;
public GameServerTCP serverTCP;
private String gamename = "-1";
public String username;
/**
* This is the future!
* Contains an exact imprint of the player of client side.
* Cheats can be detected here.
*/
private PlayerMP playerMP;
String clientSentence;
TCPConnection(Socket socket, GameServerTCP serverTCP) {
this.socket = socket;
this.serverTCP = serverTCP;
isRunning = true;
thread = new Thread(this);
thread.start();
}
public synchronized void closeConnection() {
if (MasterConnections.connectionsTCP.containsKey(getUniqueConnectionIdentifier())) MasterConnections.connectionsTCP.remove(getUniqueConnectionIdentifier());
if (this.username != null && MasterConnections.currentlyLoggedOnAccounts.contains(this.username)) MasterConnections.currentlyLoggedOnAccounts.remove(this.username);
if (this.gamename != null && serverTCP.server.games.containsKey(this.gamename)) {
Level game = serverTCP.server.games.get(this.gamename);
for (String p : game.playersInLevel) {
if (p.equals(getUniqueConnectionIdentifier())) {
game.playersInLevel.remove(p);
System.out.println(this.username + " has been been removed from game " + this.gamename + ".");
}
}
PacketTCP02LeaveGame tellOthersPacket = new PacketTCP02LeaveGame(this.gamename, this.username);
game.writeDataTCPToAllPlayersInThisLevel(tellOthersPacket);
}
try {
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(socket.getRemoteSocketAddress() + " has been disconnected from server.");
this.serverTCP.amountOfTCPConnections--;
this.stop();
}
public String getUniqueConnectionIdentifier() {
return socket.getInetAddress() + ":" + socket.getPort();
}
public String generateUniqueUDPConnectionIdentifier(InetAddress inetAddess, int udpPort) {
System.out.println("uuc created: ");
System.out.println(inetAddess + "/" + udpPort);
return inetAddess + ":" + udpPort;
}
public void run() {
//version check first
PacketTCP00VersionCheck packetVersionCheck = new PacketTCP00VersionCheck(serverTCP.server.getVersion());
if (MasterConnections.connectionsTCP.containsKey(getUniqueConnectionIdentifier())) {
this.closeConnection();
}
else {
MasterConnections.connectionsTCP.put(getUniqueConnectionIdentifier(), this);
packetVersionCheck.writeData(this);
}
BufferedReader inFromClient;
try {
inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e1) {
e1.printStackTrace();
closeConnection();
return;
}
while(isRunning) {
try {
clientSentence = inFromClient.readLine();
if (clientSentence == null) {
inFromClient.close();
closeConnection();
}
else {
System.out.println("tcprec -> " + (new Date(System.currentTimeMillis())) + " -> " + this.username + " -> " + clientSentence);
this.parsePacket(clientSentence.getBytes());
}
}
catch (SocketTimeoutException ste) {
/**
* TODO:
*/
ste.printStackTrace();
System.err.println("YOU CAN DO SOMETHING HERE!!!!!!!");
closeConnection();
}
catch (Exception e) {
e.printStackTrace();
closeConnection();
}
}
}
public void stop() {
isRunning = false;
try {
thread.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And here is my client:
public class GameClientTCP extends Thread {
public String gamestate = "logged out";
private Game game;
public Socket tcpSocket;
public boolean isRunning = false;
private String serverSentence;
public boolean hasBeenStarted = false;
public int boundUDPPort = -1;
public static String[] characters = new String[5];
public static boolean charactersAreLoaded = false;
private PrintWriter toServer;
public GameClientTCP(Game game, String ipAddress) {
this.game = game;
}
public boolean tryConnect() {
try {
tcpSocket = new Socket();
tcpSocket.connect(new InetSocketAddress(Settings.SERVER_ADDRESS, 6336), 1000);
System.out.println("Just connected to " + tcpSocket.getRemoteSocketAddress());
game.getSocketClientUDP().prepareBeforeStart();
game.getSocketClientUDP().start();
return true;
} catch (UnknownHostException e1) {
try {
tcpSocket.close();
} catch (IOException e) {
GameError.appendToErrorLog(e);
return false;
}
return false;
} catch (IOException e1) {
try {
tcpSocket.close();
} catch (IOException e) {
GameError.appendToErrorLog(e);
return false;
}
GameError.appendToErrorLog(e1);
return false;
}
}
public void run() {
BufferedReader fromServer;
try {
fromServer = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
toServer = new PrintWriter(tcpSocket.getOutputStream(),true);
} catch (IOException e1) {
GameError.appendToErrorLog(e1);
return;
}
while(isRunning) {
try {
serverSentence = fromServer.readLine();
//System.out.println("Received: " + serverSentence);
if (serverSentence != null) this.parsePacket(serverSentence.getBytes());
}
catch(UnknownHostException ex) {
GameError.appendToErrorLog(ex);
}
catch(IOException e){
GameError.appendToErrorLog(e);
}
catch(Exception e) {
GameError.appendToErrorLog(e);
}
}
}
public void sendMessageToServer(String message) {
try {
toServer.println(message);
toServer.flush();
}
catch (Exception e) {
GameError.appendToErrorLog(e);
System.exit(-1);
}
}
}
I hope to find out more about this issue, please help! :)
EDIT: It may be important to say, that while my program is running, it can occur, that there are no tcp packets sent over a longer period of time. The timeout always happens, when i dont send any packets for at least 20 or 30 minutes and then when i send one again, another client times out.
As it turned out, tcp sockets, that are not used longer than a certain amount of time will be kind of destroyed by peers and therefore lose their connection.
I solved my issue, by sending a nearly empty tcp packet every minute to make it clear to all programs and services, that these sockets are alive!
I want to run a java server program in my ubuntu computer through terminal but the problem is that once I start the program I can not stop it (the program is running in the terminal and waiting for the client).
This is my code:
import java.net.*;
import java.io.*;
public class EchoServer2 extends Thread {
protected Socket clientSocket;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(2000);
System.out.println("Connection Socket Created");
try {
while (true) {
System.out.println("Waiting for Connection");
new EchoServer2(serverSocket.accept());
}
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
} catch (IOException e) {
System.err.println("Could not listen on port: 2000.");
System.exit(1);
} finally {
try {
serverSocket.close();
} catch (IOException e) {
System.err.println("Could not close port: 2000.");
System.exit(1);
}
}
}
private EchoServer2(Socket clientSoc) {
clientSocket = clientSoc;
start();
}
public void run() {
System.out.println("New Communication Thread Started");
try {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Server: " + inputLine);
out.println(inputLine);
if (inputLine.equals("Bye."))
break;
}
out.close();
in.close();
clientSocket.close();
} catch (IOException e) {
System.err.println("Problem with Communication Server");
System.exit(1);
}
}
}
I know that I can kill the process but I don't want to stop the program forcefully. I want to know: how can I stop the program safely? How can I implement this in my code?
Let's get it clear, you block the main thread at client acception. It will be no real way to cleanly close the program.
My solution would be to run a separate thread, that will do the acception job.
To illustrate, here's my code:
This is the acception thread:
private static Thread acception = new Thread("Acception Thread") {
public void run() {
try {
while (true) {
System.out.println("Waiting for Connection");
new EchoServer2(serverSocket.accept());
}
-> } catch (SocketException e) {
-> if(serverSocket.isClosed())
-> System.out.println("Connection Closed.");
-> }
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
}
};
Here's the modified main method:
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(2000);
System.out.println("Connection Socket Created");
-> acception.start();
} catch (IOException e) {
System.err.println("Could not listen on port: 2000.");
System.exit(1);
}
//support to close, using the command line.
Scanner scn = new Scanner(System.in);
String s = scn.next();
while(true) {
if("quit".equals.(s)) {
try {
serverSocket.close();
} catch (IOException e) {
System.err.println("Could not close port: 2000.");
System.exit(1);
} finally {
break;
}
}
s = scn.next();
}
}
You can hit the Ctrl + C keys and it will send a SIGINT (interrupt) to your program. If you don't have specific logic to run at the program shutdown it'd probably do the job.
If you have some logic to run at program shutdown, check this answer.
Check this link http://www.oracle.com/technetwork/java/javase/signals-139944.html Should help you
Edit:
Solution 1: Add this to your main method
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Prepare to exit");
//some cleaning up code...
}
});
Solution 2: Add another thread which waits for "exit" command, SOmething like:
new Thread() {
#Override
public void run() {
System.out.println("Type exit to exit;-)");
Console c = System.console();
String msg = c.readLine();
if (msg.equals("exit")) {
//some cleaning up code...
System.exit(0);
}
}
}.start();
A few days ago i tried to create a server - client or client Server as an experiment to learn about socket using a thread but then someone told me that i should use swingWorker. I did some research how to use and have implemented it in as practice but it still doesn't work. the swingWorker thread doesn't look like it is running even tho i get a connection and have used .excute(). If you guys can help spot where i am doing wrong that will be great. SwingWorker class is in the startSever() and startClient() method.
private void startServer() {
SwingWorker <Void, String> runningServer = new SwingWorker<Void, String>(){
protected Void doInBackground() {
try {
listeningSocket = new ServerSocket(port);
System.out.println("waiting for connection");
connection = listeningSocket.accept();
connected = true;
System.out.println("Connected");
String incomeMessage =null;
while(connected){
inStream = connection.getInputStream();
inDataStream = new DataInputStream(inStream);
if (myMessage !=null){
outStream = connection.getOutputStream();
outDataStream = new DataOutputStream(outStream);
outDataStream.writeUTF(myMessage);
}
if((incomeMessage = inDataStream.readUTF())!=null){
clientMessage = incomeMessage;
publish(clientMessage);
incomeMessage =null;
}
}
} catch (IOException e) {
clientMessage = "Connection Lost";
}
return null;
}
runningServer.execute();
}
Here's a VERY basic example.
Basically, because you program requires asynchronous communications (that is, you need to be able to read from the socket AND write to it at the same time), you need to offload each stream to a separate thread.
The management process of this example is, well, no existent. Realistically, you should have some kind of "connection" manager that would be able to cleanly close the output and input threads so that, for example, when the user types "bye", the output thread would be able to tell the connection manager that the connection should be terminated. It would then tell the input thread to stop reading any new message and terminate...
Client
public class Client {
public static void main(String[] args) {
try {
Socket master = new Socket("localhost", 8900);
new Thread(new InputHandler(master)).start();
new Thread(new OuputHandler(master)).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static class InputHandler implements Runnable {
private Socket socket;
public InputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (commune) {
String text = reader.readLine();
System.out.println("\n<server> " + text);
if (text.toLowerCase().equals("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
public static class OuputHandler implements Runnable {
private Socket socket;
public OuputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner = new Scanner(System.in);
while (commune) {
System.out.print("> ");
String text = scanner.nextLine();
writer.write(text);
writer.newLine();
writer.flush();
if (text.equalsIgnoreCase("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
writer.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
Server
public class Server {
public static void main(String[] args) {
try {
ServerSocket master = new ServerSocket(8900);
Socket socket = master.accept();
new Thread(new InputHandler(socket)).start();
new Thread(new OuputHandler(socket)).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static class InputHandler implements Runnable {
private Socket socket;
public InputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (commune) {
String text = reader.readLine();
System.out.println("\n<client> " + text);
if (text.toLowerCase().equals("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
public static class OuputHandler implements Runnable {
private Socket socket;
public OuputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner = new Scanner(System.in);
while (commune) {
System.out.print("> ");
String text = scanner.next();
writer.write(text);
writer.newLine();
writer.flush();
if (text.equalsIgnoreCase("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
writer.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
Update (whine)
While I have your source code in front of me...
There should very, very, rarely be a need to do textMessage.addKeyListener(this)
Because you are using a JTextField, you should be using a ActionListener instead. There are a a number of important reasons for this, but for you, the main one would be the fact that a "accept" action is Look and Feel dependent. While most systems do use Enter as there "accept" action, is not a guarantee.
Have a look at How to Write a Action Listener for more information
Given the general complexity of what you are trying to do, +1 for a overall good attempt!
Using this example, the following changes work with a single telnet client.
private PrintWriter out;
...
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
myMessage = friendLabel + textMessage.getText();
if (out != null) {
out.println(myMessage);
}
...
}
...
protected Void doInBackground() {
try {
listeningSocket = new ServerSocket(port);
System.out.println("Waiting for connection");
connection = listeningSocket.accept();
connected = true;
System.out.println("Connected");
Scanner in = new Scanner(connection.getInputStream());
out = new PrintWriter(connection.getOutputStream(), true);
publish("Connected");
while (true) {
publish(in.nextLine());
}
} catch (IOException e) {
clientMessage = "Connection Lost";
try {
connection.close();
System.out.println("Closed");
} catch (IOException e1) {
e1.printStackTrace();
connected = false;
}
}
return null;
}
I see your server port is 8900 and your client port is 8900 too. I am not sure if it matters if the server and client are running on the same machine...
I am implementing a simple client-server architecture where multiple clients should be able to connect to the server and strings could be exchanged between the server and client.
My idea is that I'll have two threads on each side: a listener, constantly checking if there is anything new in the inputstream, and a writer thread, that writes into the socket if there is something to write.
However, the second thread doesn't even start... Only the first sysout is displayed.
//start new thread to handle client input
new Thread(
new ServerWorker(clientSocket, this, this.getIdCounter())).start();
System.out.println("server side listener started");
//start new thread to handle client output
new Thread(new ServerWorkerListener(clientSocket)).start();
System.out.println("server side writer started");
Here is some code from the ServerWorker:
public void run() {
try {
OutputStream output = clientSocket.getOutputStream();
while (true) {
// output.write(("Pling!\n\n").getBytes());
for (Client tempClient : server.getClientList()) {
if ((tempClient.getId() == this.id)
&& tempClient.isShouldSend()) {
output.write((tempClient.getOutputStream() + "\n\n")
.getBytes());
tempClient.setInputStream("");
tempClient.setShouldSend(false);
}
}
}
} catch (IOException e) {
System.out.println("Error in serverWorker");
e.printStackTrace();
}
}
I really don't know what I'm missing...
Whole of ServerWorker:
public class ServerWorker implements Runnable {
protected Socket clientSocket = null;
protected String serverText = null;
protected int id;
protected Server server;
public ServerWorker(Socket clientSocket, Server server,
int id) {
this.clientSocket = clientSocket;
this.serverText = serverText;
this.id = id;
this.server = server;
}
public void run() {
try {
OutputStream output = clientSocket.getOutputStream();
while (true) {
// output.write(("Pling!\n\n").getBytes());
for (Client tempClient : server.getClientList()) {
if ((tempClient.getId() == this.id)
&& tempClient.isShouldSend()) {
output.write((tempClient.getOutputStream() + "\n\n")
.getBytes());
tempClient.setInputStream("");
tempClient.setShouldSend(false);
}
}
}
} catch (IOException e) {
System.out.println("Error in serverWorker");
e.printStackTrace();
}
}
}
Whole of ServerWorkerListener:
public class ServerWorkerListener implements Runnable {
private BufferedReader input;
private Socket clientSocket;
public ServerWorkerListener(Socket clientSocket) {
this.clientSocket = clientSocket;
run();
}
#Override
public void run() {
System.out.println("its running");
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
while (true) {
System.out.println("it's looping");
String inputLine = null;
if ((inputLine = in.readLine()) != null) {
JOptionPane.showMessageDialog(null, inputLine, "InfoBox: "
+ "Message from client",
JOptionPane.INFORMATION_MESSAGE);
}
}
} catch (UnknownHostException e) {
System.err.println("Don't know about client");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to client");
System.exit(1);
}
}
}
You are invoking run() inside the constructor of ServerWorkerListener, which you must not do. The new thread ought to invoke run(), otherwise, since it contains an infinite loop, it will never return from the constructor and hence never invoke the Thread’s constructor, not to speak of its start method. So removing run() the invocation from the constructor should solve the problem.
I am writing a single p2p file sharing program that will accept connections and also serve as server itself.
Its in process but Line: 60
Socket sock1= tcpSocket.accept();
throws a Null pointer Exception and i don't know whats wrong. Tried everything.
import java.net.*;
import java.io.*;
public class echoer implements Runnable {
int i,backlog;
public Socket tcpClient= null;
public ServerSocket tcpSocket= null;
public echoer(int tcpPort, int udpPort, int backlog) {
try {
this.tcpSocket = new ServerSocket(tcpPort,backlog);
System.out.println("Server connected to "+ InetAddress.getLocalHost() + "on TCP port " + tcpPort + "and UDP port " + udpPort );
this.backlog= backlog;
listening();
}
catch (SocketTimeoutException s) {
System.out.println("timeout");
}
catch (IOException ioe) {
System.out.println("could not listen on port 10009");
System.exit(-1);
}
}
public echoer () {
}
void listening(){
try {
//i++;
tcpSocket.getInetAddress();
System.out.println();
//Thread t1= new Thread((Runnable) new AcceptInput());
//t1.start();
//tcpSocket.accept();
//System.out.println("Connection accepted");
//messaging();
Thread t2 = new Thread((Runnable) new echoer());
t2.start();
}
catch (Exception e) {
System.out.println("Cannot accept connection");
}
}
public void Client(String addr, int port) throws IOException
{
System.out.println("address= "+ addr+ "port= "+ port);
tcpClient = new Socket(addr,port);
}
/*void messaging () {
System.out.println("Starting Thread");
Thread t = new Thread((Runnable) new echoer());
t.start();
}*/
public void run() {
while (true) {
try {
//System.out.println("Listening on "+ InetAddress.getLocalHost().getHostAddress() + "on TCP port " + tcpSocket.getLocalSocketAddress());
Socket sock1= tcpSocket.accept();
//Client(InetAddress.getLocalHost().getHostAddress(),tcpSocket.getLocalPort());
System.out.println("Connection accepted");
ObjectOutputStream out= new ObjectOutputStream(sock1.getOutputStream());
//Now start the messaging thread nad pass this sock1 to tcpClient
/*String line;
System.out.println("Write a message");
DataInputStream din= new DataInputStream(tcpClient.getInputStream());
line= din.readUTF();
if (line == null) {
din.close();
tcpClient.close();
}
System.out.println("Recvd message:" + line);*/
if (sock1 != null) {
tcpSocket.close();
}
}
catch (IOException o) {
System.out.println("Read Failed");
}
}
}
/*catch (IOException i) {
System.out.println("Last statement");
}
}*/
public static void main(String[] args) {
new echoer(Integer.parseInt(args[0]),Integer.parseInt(args[1]),5);
}
}
class AcceptInput implements Runnable {
String token;
public void run () {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
try {
token= br.readLine();
if (token== "connect" ) {
System.out.print("Enter IP address: ");
BufferedReader ip= new BufferedReader(new InputStreamReader(System.in));
//accept ip and port
// pass ip and port to tcpclient socket to initiate a connection
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here's the current problem, you call new Thread((Runnable) new echoer()) and this starts your thread.
However this calls the empty default constructor for echoer which currently has no actual code in it!
So even though you construct the sockets once, after you do that you just create a new instance of echoer with all new sockets and call run() on that
This means that all the sockets in run are null because they were never set and therefore through a NullPointerException when you try to use them.