ServerSocket blocked by thread seeking input from console - java

Can anyone give me insight into why the ServerSocket constructor never returns in the new thread? (I never see the "Opened" message printed to the console.) It seems the main thread prevents the server socket thread from running by entering into readLine too quickly:
public class Main
{
public static void main(String[] args) throws IOException
{
new Thread(new SocketOpener()).start();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inLine = br.readLine();
System.out.println(inLine);
}
}
public class SocketOpener implements Runnable
{
public void run()
{
try
{
System.out.println("Opening...");
ServerSocket socket = new ServerSocket(4444);
System.out.println("Opened");
}
catch (IOException ex)
{
System.out.println("IO Error");
}
}
}

I don't think that it's the ServerSocket constructor that blocks, but the System.out.println("Opened"). The fact that the main thread is trying to read from System.in prevents outputs to be done on System.out.

Reading from System.in causes a lot of problems:
Under some circumstances you can't:
Create a Temp-File (because of 2)
Read the Inet4Adress of your maschine
Load a DLL
I've encountert some of this Problems with Windows Server 2003 and older. This happens because of some Bugs in the Win32-API ans Java-VM.
But there may be an easy workarround:
Only call System.in.read(), if System.in.availiable() returns a value larger than 0.
Deadlock between
System.loadLibrary() and
System.in.read()
Inet4AddressImpl.getLocalHostName is
hanging intermittenly
Deadlock
in Win32

Related

I'm trying to use java to run a Terraria dedicated console server but there are some problems

I want to realize some functions to automatically control the server. For instance, there's a command of Terraria dedicated server "Time" which shows the current time in game. I want to use another function dawn to reset the time at 12:00 AM in the game. So, I need to handle the input and output of the console server. To realize it, I'm using getRuntime() and I create 3 threads for the console server: inputstream, outputstream and errstream.
Here is my code for creation of the server process.
public static void main(String[] args) throws IOException, InterruptedException {
String path="F:\\Steam\\steamapps\\common\\Terraria\\TerrariaServer.exe";
Process p=Runtime.getRuntime().exec(path);
Thread errThread=new Thread(new ErrorCatcher(p.getErrorStream()));
Thread readThread=new Thread(new Reader(new BufferedReader(new InputStreamReader(p.getInputStream()))));
Thread writeThread=new Thread(new Sender(new BufferedWriter(new OutputStreamWriter(p.getOutputStream()))));
errThread.start();
readThread.start();
writeThread.start();
p.waitFor();
}
When directly running the server, it should look like this:
enter image description here
But after running it in the java:
- Terraria Server v1.4.0.5
1 Boss Training
2 Depths of Indignity
3 Fraternity of Gel
4 Powerful Defecation
5 Sule
6 The Dank Lake
n New World d
<number> Delete World
There are no such words "Choose World" and the process stops here. Process doesn't end and looks like gets into an endless loop. When entering some instructions to the server, there are not any responses. Then, I found there are 2 subprocesses under the main process when running the server, one is called "Terraria.exe" and another is "conhost.exe". When I use Task manager to detroy the Terraria.exe, the words "Choose World" appears but when sending commands, it shows the "java.io.IOException: Broken pipe". I guess that terraria.exe is the real server process and the conhost.exe is just a controler to show output and get input.
After that I added configrations of server to make the server directly start without choosing some options in the console.
Here is the code:
public static void main(String[] args) throws IOException, InterruptedException {
String path="cmd /c F:\\Steam\\steamapps\\common\\Terraria\\TerrariaServer.exe -config F:\\Steam\\steamapps\\common\\Terraria\\config1.txt";
Process p=Runtime.getRuntime().exec(path);
Thread errThread=new Thread(new ErrorCatcher(p.getErrorStream()));
Thread readThread=new Thread(new Reader(new BufferedReader(new InputStreamReader(p.getInputStream()))));
Thread writeThread=new Thread(new Sender(new BufferedWriter(new OutputStreamWriter(p.getOutputStream()))));
errThread.start();
readThread.start();
writeThread.start();
p.waitFor();
}
It works well, here are some information of the output:
Terraria Server v1.4.0.5
Listening on port 7777
Type 'help' for a list of commands.
: Server started
It looks like the server is running normally and I tried to play in the server, everything is ok.
But, still no responses when entering some instructions.
Here is the code of 3 threads(read,write and error):
read:
public static class Reader implements Runnable {
BufferedReader br;
Reader(BufferedReader br)
{
this.br=br;
}
#Override
public void run() {
String line="";
while(true)
{
try {
line=br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if(line!=null) {
System.out.println(line);
}
}
}
}
err:
public static class ErrorCatcher implements Runnable{
InputStream error;
ErrorCatcher(InputStream error)
{
this.error=error;
}
#Override
public void run() {
try {
for (int i = 0; i < error.available(); i++) {
System.out.println("" + error.read());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
write:
public static class Sender implements Runnable{
BufferedWriter bw;
Sender(BufferedWriter bw)
{
this.bw=bw;
}
#Override
public void run() {
String cmd;
while(true)
{
try{
BufferedReader bufferRead = new BufferedReader(new InputStreamReader(System.in));
cmd = bufferRead.readLine();
if(cmd.equals("quit"))
{
break;
}
bw.write(cmd+"\n");
bw.flush();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
I don't konw where the problem is. It seems like server can be controled by programm in this way. I also had an idea to get the subprocess of server - conhost.exe because I thought the problem is in the terraria.exe. But I didn't find the way to get the suprocess from its parent.

Java: Multithreading with two different input sources and reacting

First question here on StackOverflow, so please excuse me if I ask this incorrectly.
Basically, I'm writing a Multicast Client that indefinitely listens to a multicast address until the user types "quit" into the console. I've found that setting SO_TIMEOUT for the MulticastSocket, checking if "quit" has been typed, and then returning to the receive method call doesn't really work since a packet could be sent right after the timeout and the check of the console blocks. So I believe the best option is to simply have 2 threads going where one listens on the socket and blocks until it receives something, and the other thread listens to the console until told to quit. The only issue I have is that I'm unsure of how to go about having the console listening thread tell the socket thread to close the socket and terminate. System.end() would work but I fear that I'd leave a socket open, etc.
TLDR; Is there a way for the main method of a class to start a thread, and then respond a specific way once that thread ends? I need to listen to the console on one thread and a MulticastSocket on another, or just in the main of the client class.
Thanks everyone.
I would call Socket.close() to close the socket. This will produce an IOException in that thread. so before doing this I would set a flag like closed = true; and have the other thread check this before printing the error i.e. don't print an IOException if you have been closed. Something like this.
public class SocketListener implements Runnable, Closeable {
final MulticastSocket socket;
final Consumer<DatagramPacket> packetConsumer;
volatile boolean closed;
public SocketListener(MulticastSocket socket, Consumer<DatagramPacket> packetConsumer) {
this.socket = socket;
this.packetConsumer = packetConsumer;
}
#Override
public void run() {
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
try {
while(!closed) {
socket.receive(packet);
packetConsumer.accept(packet);
}
} catch (IOException e) {
if (!closed)
e.printStackTrace();
}
}
#Override
public void close() throws IOException {
closed = true;
socket.close();
}
}
for example, in your main thread you can do
MulticastSocket socket = ...
Consumer<DatagramPacket> packetConsumer = ...
try (SocketListener listener = new SocketListener(socket, packetConsumer)) {
boolean finished = false;
do {
// read from the console
if (some condition)
finished = true;
} while(!finished);
} // calls close() for you.

Reading from a Java TCP socket in a thread

i have this TCP socket (i only posted relevant parts and removed exception throwings):
static Socket clientSocket;
static BufferedReader inFromServer;
The connection part (i call it from another class):
static Socket clientSocket = new Socket(ip, port);
static BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
And to recieve text i have a runnable thread wich i call like this:
public static void StartRecievingText(){
TCPScanner.setReader(inFromServer);
Thread t1 = new Thread(new TCPScanner());
t1.start();
}
The thread:
public class TCPScanner implements Runnable {
static BufferedReader inFromServer;
public static void setReader(BufferedReader reader){
inFromServer = reader;
}
public void run() {
while (true) {
String temp = inFromServer.readLine();
System.out.println(temp);
}
}
}
The thread runs to the inFromServer.readline() part and appears to recieve nothing.
It's my first time working with threads and ...well second time working with tcp connections so i don't know if i've done anything wrong.
Thanks for your help (and sorry for spelling mistakes... still learning english)
Your client is reading lines but you aren't sending lines, so the client blocks forever waiting for a line terminator that never arrives. Either add a newline to what is being sent, or use another read method that doesn't require it.
There are other problems with your code. None of these data items should be static. Your read loop should test the result of readLine() for null, and close the socket and exit if true.

How can I close the socket in a proper way? [duplicate]

This question already has an answer here:
Proper way to close an AutoCloseable
(1 answer)
Closed 3 years ago.
This is a simple TCP server. How can i close the socket when the program is terminated?
I have using try/finally and try to close the socket. But it doesn't run the finally block when I exit the program.
Anyone can have idea on how to close the socket in a proper way?
try {
socket = new ServerSocket(port);
System.out.println("Server is starting on port " + port + " ...");
}catch (IOException e){
System.out.println("Error on socket creation!");
}
Socket connectionSocket = null;
try{
while(true){
try{
connectionSocket = socket.accept();
Thread t = new Thread(new ClientConnection(connectionSocket));
t.start();
}catch (IOException e) {
System.out.println("Error on accept socket!");
}
}
}finally{
this.socket.close();
System.out.println("The server is shut down!");
}
After creating your ServerSocket, you could add a ShutdownHook to close it on JVM termination, something like this:
Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
try {
socket.close();
System.out.println("The server is shut down!");
} catch (IOException e) { /* failed */ }
}});
Invoking ServerSocket#close will terminate the blocking ServerSocket.accept call, causing it to throw a SocketException. However, note that your current handling of IOException in the while loop means you will then re-enter the while loop to attempt accept on a closed socket. The JVM will still terminate, but it's a bit untidy.
Shutdown hooks do not run if you terminate a console application in Eclipse (on Windows at least). But they do run if you CTRL-C Java in a normal console. For them to run, you need the JVM to be terminated normally, e.g. SIGINT or SIGTERM rather than SIGKILL (kill -9).
A simple program which you can execute in Eclipse or a console will demonstrate this.
public class Test implements Runnable {
public static void main(String[] args) throws InterruptedException {
final Test test = new Test();
Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
test.shutdown();
}});
Thread t = new Thread(test);
t.start();
}
public void run() {
synchronized(this) {
try {
System.err.println("running");
wait();
} catch (InterruptedException e) {}
}
}
public void shutdown() {
System.err.println("shutdown");
}
}
No need in your particular case, the operating system will close all the TCP sockets for you when the program exits.
From javadoc :
The Java runtime automatically closes the input and output streams,
the client socket, and the server socket because they have been
created in the try-with-resources statement.
Also
The finalize() method is called by the Java virtual machine (JVM)
before the program exits to give the program a chance to clean up and
release resources. Multi-threaded programs should close all Files and
Sockets they use before exiting so they do not face resource
starvation. The call to server.close() in the finalize() method closes
the Socket connection used by each thread in this program.
protected void finalize(){
//Objects created in run method are finalized when
//program terminates and thread exits
try{
server.close();
} catch (IOException e) {
System.out.println("Could not close socket");
System.exit(-1);
}
}
Howcome the finally is not run? Probably the while(true) should be replaced with something like
while (!shutdownRequested)
alternatively you can create a shutdown hook that handles the socket close
Well, how do you "exit" the program? finally will be executed if an exception will be thrown or if the try block finishes its execution in a "normal" way but I think that might be "hard" because of your while(true).
To close the socket you should use socket.close() and I would recommend you not to rely on the destroy function.

Filedialog is killing my thread

Im working on a socket program in Java.
Im running a GUI with a socket server in the background.
The socket server is running a thread that checks for socket messages every 10ms.
Both of them runs fine together but as soon as I try to open my File dialog in the gui, the gui crashes, but the server keeps on running.
Im thinking that I run the server (or the server thread) in a wrong way.
The file dialog works fine if I skip the socket.
What could be the problem, could it be that Im running the thread in a wrong way?
(this in one class)
public ServerController(){
ServSocket st = new ServSocket();
Thread thread1=new Thread(st);
thread1.start();
}
(this is my thread)
public void run(){
while (true) {
try {
Thread.sleep(10);
}
catch (InterruptedException e) {}
switch (Status) {
case CONNECTED:
try {
socket = new Socket(hostIP, port);
System.out.println("Connected on: " + hostIP + port);
out = new PrintWriter(socket.getOutputStream(), true);
changeStatus(STARTSENDING, true);
}
catch (IOException e) {
System.out.println("disconnected");
}
break;
(and this is my main)
static ServerController scon;
static Controller cn;
public static void main(String[] args) {
scon = new ServerController();
cn = new Controller();
cn.gui();
}
Just guessing here, but I think it's relating to the EDT.
Are you trying to launch the dialog from outside the EDT? http://en.wikipedia.org/wiki/Event_dispatching_thread
If you think you might be, try using SwingUtilities static methods (specifically isEventDispatchThread and invokeLater) to hone in and rectify the issue:
http://java.sun.com/javase/6/docs/api/javax/swing/SwingUtilities.html#isEventDispatchThread()
http://java.sun.com/javase/6/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)
hth
The problem is now solved.
Seems that the problem was that i had a scanner that was waiting for input(string = sc.next();) every 10ms in the thread, and after a few input my GUI showed.
I removed the Scanner and i now have a working application.

Categories

Resources