The project is a chat program with a multi-threaded server to handle multiple clients. The code below is server-side for the thread that begins once a client connects. The ConnectionHandler takes a connected clients socket and 'ID'.
The static "broadcast" method called in run() is not relevant to the question as well as both functions in the finally clause.
I have been working on the project on both a Windows 10 desktop, and an XPS laptop running Ubuntu 18.04.
Client disconnection is handled once the IOException is caught in the run() method. This works as designed on Windows, however for Ubuntu that is not the case. When exiting the GUI client it seems like only the exception is caught on Windows and doesn't happen on Ubuntu. Thus rendering the server non-working for Linux and working perfectly on Windows.
Is this not a well practiced method to handle a client disconnection in general? Or is it something else that I need to change in order for this to work on Linux? I have no idea what to do because I'm not sure if it's an error in my code or it's just the way Linux handles Java versus Windows?
Any help or tips is appreciated. Thanks in advance.
class ConnectionHandler implements Runnable
{
//Begin declarations for new client thread
int clientId;
Socket connection;
BufferedReader reader;
BufferedWriter writer;
String message;
//end declarations for new client thread
public ConnectionHandler(int clientId, Socket connection)
{
this.clientId = clientId;
this.connection = connection;
}
#Override
public void run()
{
try
{
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
}
catch (IOException e)
{
e.printStackTrace();
}
try
{
while (true)
{
message = reader.readLine();
if (message != null)
{
System.out.println("Message from " + message);
CrosstalkServer.broadcast(message);
}
}
}
catch (IOException e)
{
System.out.println("Client has disconnected. Recycling client ID: " + clientId);
}
finally
{
//Close the reader, writer, and socket.
terminateClient();
//Client has disconnected, handle client count and recycle client ID
CrosstalkServer.recycleClientId(this);
}
}
Edit: I tested the program on Windows 10, Windows 7, and Ubuntu 18.04. After some testing, it is the client side causing the problem. I ran the server on my Ubuntu laptop, and tested a Windows 7 client along with a Windows 10 clients. The Windows 7 client did not cause an IOException to be thrown, while Windows 10 did. Ubuntu client-side does not cause the IOException either.. What is a better way to determine a client disconnection? Start a thread to monitor by attempting to constantly write to each client in my client arraylist?
Related
I have the following application
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
try
{
var listener = new HttpListener();
listener.TimeoutManager.RequestQueue = TimeSpan.FromSeconds(10);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
Console.ReadLine();
}
}
}
The output of the application is as follows
System.PlatformNotSupportedException: Operation is not supported on this platform.
at System.Net.HttpListenerTimeoutManager.set_RequestQueue(TimeSpan value)
at ConsoleApp2.Program.Main(String[] args) in C:\Users\a\source\repos\ConsoleApp2\ConsoleApp2\Program.cs:line 13
Unhandled exception. System.PlatformNotSupportedException: Operation is not supported on this platform.
at System.Net.HttpListenerTimeoutManager.set_RequestQueue(TimeSpan value)
at ConsoleApp2.Program.Main(String[] args) in C:\Users\a\source\repos\ConsoleApp2\ConsoleApp2\Program.cs:line 13
This was run on Debian but we get the same error on Alpine. No such error on Windows.
Is this truly not supported? If not, is it something that is managed within the OS?
Short answer is, if you want to run on Linux, don't use HttpListener. It's built on top of HTTP.sys which is a Windows specific kernel mode listener
There is an ongoing discussion related to deprecating HttpListener and it points to using Kestrel as an alternative
I am trying to make a game with a multiplayer option in javafx using TCP/IP connection. I created a thread that handles the connections in the background so that it will listen to connections while the user plays offline. If someone tries to connect i want the thread fire a button on the main javafx application. The problem is i can't modify a UI on another thread. I tried using Task<>, platform.runlater, and Timeline to no effect.
Thread thread = new Thread(){
public void run(){
try {
int ServerPort=6779;
ServerSocket serverSocket = new ServerSocket(ServerPort);
System.out.println("waiting for player to join");
Socket connectionSocket = serverSocket.accept();
ObjectOutputStream outToServer1 = new ObjectOutputStream(connectionSocket.getOutputStream());
System.out.println("connected");
Board boardJ = new BoardM();
outToServer1.writeObject(boardJ);
boardS=boardJ;
ServerBoard.fire();
} catch (IOException ex) {
Logger.getLogger(JavaFXApplication1.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
thread.start();
The Thread is ok here. What you have to do is to wrap the fireing of the button in a Platform.runLater call.
I'm trying to make a chat system project (still incomplete) using java, but I need small help in forwarding the client's received message.
The server is working as multi-threading so many clients can connect to it, what I want is: (Assumed scenario) if 6 clients are connected to the server, then one of them send a message, it should be forwarded to all connected clients through the server.
here is the 2 codes..
Server side
import java.io.*;
import java.net.*;
public class ChatServer implements Runnable
{
Socket csocket;
ChatServer(Socket csocket){ this.csocket = csocket; }
public static void main(String[]args)throws Exception
{
ServerSocket sersock=new ServerSocket(3000);
System.out.println("Server ready for chatting");
while(true)
{
Socket sock =sersock.accept();
new Thread(new ChatServer(sock)).start();}
}
public void run()
{
try{
System.out.println(Thread.currentThread().getName() + ": HELLO");
BufferedReader keyRead=new BufferedReader(new InputStreamReader(System.in));
OutputStream ostream=csocket.getOutputStream();
PrintWriter pwrite=new PrintWriter(ostream, true);
InputStream istream=csocket.getInputStream();
BufferedReader receiveRead=new BufferedReader(new InputStreamReader(istream));
String receiveMessage, sendMessage;
while(true) {
if((receiveMessage=receiveRead.readLine())!=null)
{
System.out.print(Thread.currentThread().getName() + ": ");
if(receiveMessage.equals("QUIT"))
Thread.currentThread().stop();
else
System.out.println(receiveMessage);}
sendMessage=keyRead.readLine();
pwrite.println(sendMessage);
System.out.flush();}
} catch (IOException e){ System.out.println(e); }
}
}
client side
import java.io.*;
import java.net.*;
public class ChatClient
{
public static void main(String[]args)throws Exception
{
Socket sock =new Socket("localhost", 3000);
// reading from keyboard (keyRead object)
BufferedReader keyRead=new BufferedReader(new InputStreamReader(System.in));
// sending to client (pwrite object)
OutputStream ostream=sock.getOutputStream();
PrintWriter pwrite=new PrintWriter(ostream, true);
// receiving from server ( receiveRead object)
InputStream istream=sock.getInputStream();
BufferedReader receiveRead=new BufferedReader(new InputStreamReader(istream));
System.out.println("Start the chitchat, type and press Enter key");
String receiveMessage, sendMessage;
while(true)
{
sendMessage=keyRead.readLine();// keyboard reading
pwrite.println(sendMessage);// sending to server
System.out.flush();// flush the data
if((receiveMessage=receiveRead.readLine())!=null)//receive from server
{
System.out.println(receiveMessage);// displaying at DOS prompt
}
}
}
}
Thanks in advance.
I write these types of server applications frequently, as a way of connection client through a relay server when direct connections between them are not possible. The solution is simple, put each socket that you receive from the accept() function into a List or Tree of your choice.
List<Socket> connectionList = new ArrayList<Socket>();
...
Socket sock =sersock.accept();
connectionList.add(sock);
...
for (Socket connection : connectionList) {
connection.getOutputStream().write(msgBytes);
}
I have the UWP app("server") running on win10 prof, this UWP app is an application service and I have another UWP app(Client), which communicates with that service using TSP/IP. How many clients running on the other win10 devices can connect to the "server" at the same time?
Using the StreamSocketListener class, I believe you can handle an unlimited number of client socket connections (depending on implementation, hardware, bandwidth, etc.). Here's a basic example of the server-side implementation of the listener using a static class.
// Define static class here.
public static StreamSocketListener Listener { get; set; }
// This is the static method used to start listening for connections.
public static async Task<bool> StartServer()
{
Listener = new StreamSocketListener();
// Removes binding first in case it was already bound previously.
Listener.ConnectionReceived -= Listener_ConnectionReceived;
Listener.ConnectionReceived += Listener_ConnectionReceived;
try
{
await Listener.BindServiceNameAsync(VMS.Current.Port);
return true;
}
catch (Exception ex)
{
Listener.ConnectionReceived -= Listener_ConnectionReceived;
Listener.Dispose();
return false;
}
}
private static async void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
var remoteAddress = args.Socket.Information.RemoteAddress.ToString();
var reader = new DataReader(args.Socket.InputStream);
var writer = new DataWriter(args.Socket.OutputStream);
try
{
// Handle communication here. You'll likely use an infinite loop of reading from the input stream until the socket is disconnected.
}
catch (Exception ex)
{
writer.DetachStream();
reader.DetachStream();
return;
}
}
There are different ways of handling stream sockets once you have both ends connected, and I had to do some research and experimentation to find a process that worked for what I was doing.
I've coded a client program that communicates with my arduino server. It had a swing button and a methog that ran a loop checking for any input from the server. I tried it with multiple instances running from different or/and the same IP and everything was fine. Now I tried implementing that same method for the socket in a app with JavaFX GUI. After I read here and there that it needs to be on a separate thread I did it as instructed and it seems to be working just fine. If I try to launch a second instance of it though,it imidiately throws NullPointerException on the line where i check socket.isConnected() && !Socket.isClosed(). The first instance continues to work just fine, but the other one just stays with the GUI open.
As I've done it with the same class but not on a new thread and with swing button, I can say that the problem is not on the server side.
I need to be able to launch as many instances of the program as I want while they all keep an open socket at all times. Any ideas on how to fix that ?
Update: I tryed recalling the initiation in the loop when socket is lost. It seems that the socket closes right after it is opened.
Here is the Class for the client:
package panelSouth;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class Networking implements Runnable{
static Socket socket;
static OutputStreamWriter out;
public void run() {
//Initializing socket - IP/PORT
String host = "192.168.1.178";
int port = 2015;
boolean connected=true;
do{
try{
socket = new Socket(host,port);
}
catch(Exception unknownHostException){
connected=false;
System.out.println("Connecting to host...");
}
}while(connected==true);
System.out.println("Connection is a success!");
System.out.println("Requesting pin states...");
//Requesting pin states on startup.
try{
out = new OutputStreamWriter(socket.getOutputStream());
out.write("r;");
out.flush();
}catch(Exception ex){
System.out.println(ex);
}
listen();
}
//Listening for incoming commands from host
public static void listen(){
try{
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream() ) );
while(socket.isConnected() && !socket.isClosed()){
States.commandProcess(in.readLine());
}
}catch(Exception ex){
System.out.println(ex);
}
}
//send commands.
static public void send(String command){
try{
out.write(command);
out.flush();
}catch(Exception ex){
System.out.println(ex);
}
}
//closing the socket and resetting the pins on host on close up.
static public void close(){
try{
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
out.write("x;");
out.flush();
socket.close();
}catch(Exception exception){
}
}
}
And here is the Main:
public static void main(String[] args) throws Exception{
Thread network = new Thread(new Networking());
network.setDaemon(true);
network.start();
launch(args);
}
I removed the loops in the defining of the socket and I put recall of the function only in the catch{} part. It seems that the loop was defining more than one socket or something and when I was actually sending data to the socket, it was another socket. Also I changed the thread handling and made it with Task which seems to work a lot better with JavaFX scene.