Java Android Sockets Threading - java

I've a client class which tries to connect to a server. But as you know you can't
execute network operations on the Main UI thread. So I've to create different threads for each operation.
Current code:
package com.example.justus.rocchat;
import android.os.AsyncTask;
import android.util.JsonWriter;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
/**
* Created by justus on 13-1-2015.
*/
public class Client
{
private String name;
private int port;
private String hostAddress;
private Socket socketClient;
private MainActivity mainActivity;
public boolean isConnected;
public Client(MainActivity mainActivity, String hostAdress, int port)
{
this.hostAddress = hostAdress;
this.port = port;
this.mainActivity = mainActivity;
}
public void send(final byte[] data)
{
Thread sendThread = new Thread(new Runnable() {
public void run()
{
try
{
DataOutputStream out = new DataOutputStream(socketClient.getOutputStream());
out.write(data);
System.out.println("writed data");
} catch (IOException ex) {
}
}
});
sendThread.start();
}
public void connect()
{
Thread connectThread = new Thread(new Runnable() {
public void run() {
try
{
System.out.println("trying to connect");
socketClient = new Socket(hostAddress, port);
isConnected = true;
}
catch(UnknownHostException ex)
{
System.out.println("ex:" + ex.getMessage());
}
catch (IOException ex)
{
System.out.println("ex:" + ex.getMessage());
}
}
});
connectThread.start();
}
}
Isn't this a little to much? Are there any better ways to handle this operations?
Already thanks for your time.

AsyncTask is the accepted way of handling asynchronous operations. It is a wrapper around the Thread class and is part of the Android SDK. They should only be used for operations that last under a few seconds, for longer operations you should use a Service.
developer.android.com/reference/android/os/AsyncTask.html

There are 2 options that you have
Use AsyncTask - much easier, object oriented that using threads but only for shortlived tasks (under 30 secs)
Use RoboSpice - https://github.com/stephanenicolas/robospice
Of the two, I prefer RoboSpice

Related

Is there any way to delay Async NIO server response in Java?

Having trouble 'delaying' the response of server, which is passed to client side.
What I'm trying to do is, just make an echoing, asynchronous, Non-blocking server with NIO package.
Then, I want to manually delay the response sent to Client, to confirm that this server handles multiple response, while not blocked by any of its clients, delays observable by naked eyes.
The main server code is :
package AsyncServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import AsyncServer.AsyncHandler.*;
public class AsyncServer {
int port = 40000;
public AsyncServer () {}
public AsyncServer(int port) {this.port = port;}
protected void start()
{
System.out.println("Async Server running at port "+this.port);
try {
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();
server.bind(new InetSocketAddress(this.port));
AcceptCompletionHandler ach = new AcceptCompletionHandler(server);
server.accept(null, ach);
System.in.read();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
package AsyncServer.AsyncHandler;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Void> {
private final AsynchronousServerSocketChannel ssc;
public AcceptCompletionHandler(AsynchronousServerSocketChannel in_ssc) {
this.ssc = in_ssc;
}
#Override
public void completed (AsynchronousSocketChannel sc, Void attachment) {
/*
This context was used in attempt to delay response sent to async client.
Does not work properly, only delaying server console output
try {
int amount = (int) (Math.random() * 20);
Thread.sleep(amount*1000);
System.out.println("slept for "+amount);
}
catch (InterruptedException e) {
e.printStackTrace();
}
*/
ssc.accept(null, this);
System.out.println("Connection Established");
ByteBuffer buffer = ByteBuffer.allocate(512);
ReadCompletionHandler rch = new ReadCompletionHandler(sc, buffer);
sc.read(buffer, null, rch);
//System.out.println("Received "+buffer.toString());
}
#Override
public void failed (Throwable T, Void attachment){
T.printStackTrace();
}
}
package AsyncServer.AsyncHandler;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.*;
public class ReadCompletionHandler implements CompletionHandler<Integer, Void> {
private final AsynchronousSocketChannel sc;
private final ByteBuffer buffer;
ReadCompletionHandler (AsynchronousSocketChannel in_sc, ByteBuffer in_buffer) {
this.sc = in_sc;
this.buffer = in_buffer;
}
#Override
public void completed (Integer bytes, Void attachment) {
WriteCompletionHandler wch = new WriteCompletionHandler(this.sc);
this.buffer.flip();
this.sc.write(this.buffer, null, wch);
Charset charset = Charset.forName("UTF-8");
String outputStr = new String(this.buffer.array()).trim();
System.out.println("Writing "+outputStr+" into return buffer");
}
#Override
public void failed (Throwable T, Void attachment) {
T.printStackTrace();
}
}
package AsyncServer.AsyncHandler;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class WriteCompletionHandler implements CompletionHandler<Integer, Void> {
private final AsynchronousSocketChannel sc;
WriteCompletionHandler (AsynchronousSocketChannel in_sc) {
this.sc = in_sc;
}
#Override
public void completed (Integer bytes, Void attachment) {
try {
sc.close();
System.out.println("Socket closed");
}
catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void failed (Throwable T, Void attachment) {
T.printStackTrace();
}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class AsyncClient {
private String ip = "localhost";
private int port = 40000;
private String payload = "00209999997778222223";
AsyncClient(String in_ip, int in_port, String in_payload)
{
this.ip = in_ip;
this.port = in_port;
this.payload = in_payload;
}
AsyncClient() {}
void start()
{
try {
AsynchronousSocketChannel sc = AsynchronousSocketChannel.open();
SocketAddress serverAddr = new InetSocketAddress(this.ip, this.port);
Future<Void> res = sc.connect(serverAddr);
System.out.println("Will connect to remote");
res.get();
System.out.println("Connection Established");
String outStr = this.payload;
ByteBuffer buffer = ByteBuffer.wrap(outStr.getBytes());
Future<Integer> sender = sc.write(buffer);
sender.get();
buffer.flip();
Future<Integer> receiver = sc.read(buffer);
System.out.println("Received : "+new String(buffer.array()).trim());
receiver.get();
buffer.clear();
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (ExecutionException e) {
e.printStackTrace();
}
}
}
Client Code components are also available in here.
So this code calls on Custom completionHandler three times.
Control flow goes to AcceptCompletionHandler -> ReadCompletionHandler -> WriteCompletionHandler, when each accept, read, write is called.
As I mentioned earlier, what I wanted to achieve was delaying whole asynchronous receive-response stream of each client thread. By running Client code on multiple threads, Say, some delays 11s, other delay less than 10s, my bare eye could catch this asynchronous operation.
However, If I run multiple threads of AsyncClient, It appears that no delay happens. Almost Instantly, the response arrives at client side. However, delays are really delaying console output of server side. Like this one. Sorry for missing timestamps!
I added semaphore acquire&release to server object itself, wrap delay syntax with semaphore acquire&release. It seems that asyncSocketStream passes their work to any other Idle thread if it meets delay. So I wrapped whole server in ExecutorService package, limiting maximum thread to one. Still, the client gets its reponse right away, and meaningless waiting of server console output happens...
Please enlighten me if I'm doing what is very bad, since I'm new to Async socket programming.

What is the best method to use ObservableLists for both GUI and background Tasks?

SSCCE:
package sample;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
ListView<Integer> root = new ListView<Integer>();
ObservableList<Integer> data = Model.getInstance().getData();
root.setItems(data);
// A Thread that simulates changes to GUI Observant List.
Thread populate = new Thread(()->{
for(int i=0;i<20000;i+=1){
int finalInstance = i;
// Changes are done on FXThread
Platform.runLater(()->{
data.add(finalInstance);
});
try{
Thread.sleep(5);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});populate.start();
// Populates at 200 elements/s
// Server Thread that Sends current status of ObservableList<Integer> data
Thread server = new Thread(()->{
try{
// Server Socket
ServerSocket ss = new ServerSocket(5555);System.out.println("SERVER ONLINE:");
while(true){
Socket s = ss.accept();
// Client Handler Thread to Handle Clients
Thread clientHandler = new Thread(()->{
try{
System.out.println("SERVER CLIENT:"+s);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
List<Integer> dataCopy = new ArrayList<Integer>();
// Get Current Status of data List that is being used in FXThread adn store in dataCopy
Semaphore waitForReadToComplete = new Semaphore(0);
Platform.runLater(()->{
System.out.println("EXPECTED LENGTH: "+data.size());
for(Integer a:data){
dataCopy.add(a);
try{
Thread.sleep(5); // Simulate delay while copying large elements
}catch (InterruptedException e){e.printStackTrace();}
}
waitForReadToComplete.release(); // Marks Read Operation Complete
});
waitForReadToComplete.acquire();// Resumes Client Thread
oos.writeObject(dataCopy);oos.flush();
s.close();
}catch (InterruptedException | IOException e){
e.printStackTrace();
}
});clientHandler.start();
}
}catch(IOException e){
e.printStackTrace();
}
});server.start();
// Client Thread that requests for current status of ObservableList<Integer> data.
Thread client = new Thread(()->{
try{
Thread.sleep(1000);
Socket s = new Socket(InetAddress.getLocalHost(),5555);
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
List<Integer> dataCopy;
dataCopy = (ArrayList<Integer>)ois.readObject();
s.close();
System.out.println("ACTUAL LENGTH RECIEVED BY CLIENT "+dataCopy.size());
}catch (IOException | ClassNotFoundException | InterruptedException e){
e.printStackTrace();
}
});client.start();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
// Singleton Class with Eager Initialization
class Model{
static Model onlyInstance = new Model();
ObservableList<Integer> data = FXCollections.<Integer>observableArrayList();
public static Model getInstance(){
return onlyInstance;
}
public ObservableList<Integer> getData(){
return data;
}
}
In this example, I intend to send over the status of the data List to a client when it connects to my Server Thread.
The problem is that every time I want to read the data List, I need to do it using a Platform.runLater() call, whose scheduling is not in my control.
I use a Semaphore to block the Server's Client Handler thread in order to make sure that the complete List is copied and then sent to the client.
As visible, This method makes my client wait for a longer period of time since copying the data List is done inside Platform.runLater().
I was wondering if there was a better way to share my data List between the FXThread and Background Threads.
EDIT:
Better wording, courtesy of #James_D
I have a model with some (possibly large amount of) data. The model is being updated by a background thread. The server has access to the model and sends the data on demand to network-connected clients. And then there's a UI, which is server-side. And I want the UI to display the current state of the model on the server-side and perform add/remove operations on the data from the UI user.
I suggest using a Model shared between the javafx Application, the modifying thread, and the server:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
public class Main extends Application {
private Model model;
#Override
public void start(Stage primaryStage) throws Exception{
ListView<Integer> listView = new ListView<>();
ObservableList<Integer> data = listView.getItems();
model = new Model();
model.getData().addListener(
(ListChangeListener<Integer>) listener -> {
listener.next();
Platform.runLater(()-> data.addAll(listener.getAddedSubList()));
}
);
populate();
new Server(model, 5555).activate();
new Client("localhost",5555).activate();
primaryStage.setScene(new Scene(listView, 300, 275));
primaryStage.show();
}
private void populate() {
Thread populate = new Thread(()->{
for(int i=0;i<20000;i+=1){
model.addData(i);
try{
Thread.sleep(50);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});populate.start();
}
public static void main(String[] args) {
launch(args);
}
}
class Model{
private final ObservableList<Integer> data = FXCollections.<Integer>observableArrayList();
private final ObservableList<Integer> readOnlyData = FXCollections.unmodifiableObservableList(data);
synchronized void addData(int i){
data.add(i);
}
public ObservableList<Integer> getData(){
return readOnlyData;
}
}
The Server definition, including ServerThread to support multiple clients:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.collections.ObservableList;
public class Server {
private final ExecutorService pool;
private final List<ServerThread> clients;
private final int portNumber;
private boolean stop;
private ServerSocket serverSocket;
private final Model model;
Server(Model model, int portNumber) {
this.model = model;
this.portNumber = portNumber;
pool = Executors.newFixedThreadPool(3);
clients = new ArrayList<>();
}
private void runServer(){
System.out.println("SERVER: Waiting for client");
try{
serverSocket = new ServerSocket(portNumber);
stop = false;
while(! stop){//do in loop to support multiple clients
Socket clientSocket = serverSocket.accept();
System.out.println("SERVER: client connected");
ServerThread st1 = new ServerThread(model.getData(), clientSocket);
pool.execute(st1);
clients.add(st1);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
closeSocket();
}
}
public void stop(){
for( ServerThread st : clients) {
st.stopServerTread();
}
stop = true;
pool.shutdown();
closeSocket();
}
public void activate(){
new Thread(()->runServer()).start();
}
private void closeSocket() {
try {
serverSocket.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
class ServerThread extends Thread {
private Socket socket = null;
private boolean stop;
private final ObservableList observableList;
public ServerThread(ObservableList<Integer> observableList ,Socket socket) {
this.observableList = observableList;
this.socket = socket;
}
#Override
public void run() {
try{
stop = false;
DataInputStream in = new DataInputStream( socket.getInputStream() );
DataOutputStream out = new DataOutputStream( socket.getOutputStream() );
String fromClient;
while(! stop){
if((fromClient = in.readUTF()) != null) {
System.out.println("SERVER: recieved message - " + fromClient);
out.writeUTF("Data size is " + observableList.size());
}
}
} catch (IOException e) {
e.printStackTrace();;
}
}
void stopServerTread(){
stop = true;
}
}
And finally the client which requests info from the server:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
public class Client{
private final int portNumber;
private final String hostName;
private boolean stop;
Client(String hostName, int portNumber ) {
this.hostName = hostName;
this.portNumber = portNumber;
}
private void runClient(){
try {
stop = false;
Socket socket = new Socket(hostName, portNumber);
DataInputStream in = new DataInputStream( socket.getInputStream() );
DataOutputStream out = new DataOutputStream( socket.getOutputStream() );
while (! stop) {
out.writeUTF("Request Size"); //any not null string to get server response
String fromServer = in.readUTF();
System.out.println(fromServer);
TimeUnit.SECONDS.sleep(1);
}
} catch (UnknownHostException e) {
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}catch (InterruptedException e){
e.printStackTrace();
}
}
public void activate(){
new Thread(()->runClient()).start();
}
public void stop(){
stop = true;
}
}
One thing that you could change is the order that your submitting your tasks. Instead of starting the client thread, then calling run later and waiting for the response. Just call Platform.runLater, populate the copy and then start the client thread. Now there is no reason for a semaphore.
// Immediately following the accept.
Platform.runLater(()->{
System.out.println("EXPECTED LENGTH: "+data.size());
List<Integer> dataCopy = new ArrayList<>(data);
Thread clientHandler = new Thread(()->{
try(ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()) ) {
System.out.println("SERVER CLIENT:"+s);
oos.writeObject(dataCopy);
oos.flush();
}catch (InterruptedException | IOException e){
e.printStackTrace();
}
});
clientHandler.start();
});
Creating a new thread each time should be replaced with an executor service of some sort. Depending on the task, consider using javafx.concurrent Task. Your server loop could be a task for example.
It's possible to expose an view of the data backing your observable list.
List<String> cowal = new CopyOnWriteArrayList<>();
ObservableList<String> data = FXCollections.observableList(cowal);
List<String> dataCopy = Collections.unmodifiableList(cowal);
I made it a copy on write array list so you can iterate over the view without getting a CCME. I called it a dataCopy to be consistent with the previous naming, but it is a view of the data.
Also, as a matter of taste, instead of });server.start(); create a new line to call server.start();

GUI frozen while waiting on an answer from the client

I'm currently having some issues running this small battleship program I am working on. I have two GUI, one for the server and one for the client. When I click the "Start Server" jButton, the program will freeze until it receives something from the client side.
Image of the GUI if it helps:
I have no issues unfreezing it by starting the client program, my issue is, how can I make it so that it just doesn't freeze while waiting? thanks a lot.
package battleship;
import javax.swing.JOptionPane;
import java.io.IOException;
import java.util.Scanner;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
/**
*
* #author ftonye
*/
public class BackGroundCom implements Runnable {
private int port;
private ServerSocket ss;
private Socket cs;
private Scanner reader;
private PrintStream writer;
public int missileIncomming;
public int missileOutgoing;
public Boolean dataToSend;
InetAddress sa = null;
public BackGroundCom(int port) {
this.port = port;
dataToSend = true;
missileOutgoing = 100;
startServer();
}
private void startServer() {
try {
sa = InetAddress.getLocalHost();
System.out.println(sa);
} catch (UnknownHostException ex) {
Logger.getLogger(BackGroundCom.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Server started");
try {
ss = new ServerSocket(this.port);
cs = ss.accept();
JOptionPane.showMessageDialog(null, "Server accept connection from" + cs.getInetAddress().getHostAddress());
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
}
System.out.println("Server accept connection");
}
Part of my BattleSea.java, which is where I click the button before it freezes:
btnStartServer = new JButton("Start Server");
btnStartServer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
com = new BackGroundCom(Integer.parseInt(txtPortNumber.getText().toString()));
t = new Thread(com);
t.start();
}
});
I am trying to understand how to get it to never freeze. Thanks
I expect that it is the call cs = ss.accept(); that is blocking. This is going to block until the client connects to the server. You run this in response to pushing the button, because in your button action code, you construct a BackGroundCom, and that object's constructor calls startServer, which executes this accept() line directly.
It seems like you are trying to set up the BackGroundCom object so that what it does occurs in a background thread, but what I describe above all happens before you create and run the thread. Maybe what you want to do is move the startServer call into the run() method of the BackGroundCom object. I don't see a run() method in BackGroundCom, although it implements Runnable. I assume it's further down in the code. Without it, this code wouldn't even compile.
Steve is right. ServerSocket.accept(); method will block until a connection is made. You have to put it inside another Thread so it won't block the EDT(Event Dispatching Thread). EDT is where your GUI runs.
public BackGroundCom(int port) {
this.port = port;
dataToSend = true;
missileOutgoing = 100;
new Thread(() -> (startServer()).start(); // run in new thread
}

How to create an event in Java

I am currently working on a multi-threaded socket based Java program that should allow multiple threads to send request to this program. This should be handled with the event activation but I am having hard time understanding events and their implementation. Below is the code that should allow more than 1 thread to communicate with the program but I only have 1 thread there. Can someone please shed more light on this? Much appreciated.
//this is a a threads class
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Niti implements Runnable {
public String line;
public Socket soc;
public boolean active=true;
public Niti(Socket soc)
{
this.soc=soc;
this.line=line;
this.active=active;
}
public synchronized void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(soc.getInputStream()));
line=br.readLine();
while(line!=null && !line.equals("")){
if(!this.active)
break;
System.out.println(line);
line=br.readLine();
}
BufferedOutputStream bos = new BufferedOutputStream(soc.getOutputStream());
bos.write("Poruka iz Programa".getBytes());
}
catch (IOException ex) {
Logger.getLogger(Niti.class.getName()).log(Level.SEVERE, null, ex);
}
try {
soc.close();
} catch (IOException ex) {
Logger.getLogger(Niti.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
//and this is the main class
public class Server{
public static synchronized void main(String[] args) throws IOException, InterruptedException{
ServerSocket ss = new ServerSocket(1000);
while(true){
Socket sokit = ss.accept();
Niti n = new Niti(sokit);
while(true){
Thread t = new Thread(n);
t.start();
//Thread.sleep(4000);
//n.active=false;
System.out.println("nit broj:" + Thread.currentThread().getId());
}
}
}
}
Well, without look to Niti class (that is the client handler class as I suppose) you have a logic error here:
while(true){
Socket sokit = ss.accept();
Niti n = new Niti(sokit);
while(true){ // LOGIC ERROR!!!
Thread t = new Thread(n);
t.start();
//Thread.sleep(4000);
//n.active=false;
System.out.println("nit broj:" + Thread.currentThread().getId());
}
}
With the above code you are creating infinit Threads after pass the first time through accept method. What you have to do is to remove the second while(true), like this:
while(true){
Socket sokit = ss.accept();
Niti n = new Niti(sokit);
Thread t = new Thread(n);
t.start();
//Thread.sleep(4000);
//n.active=false;
System.out.println("nit broj:" + Thread.currentThread().getId());
}

NullPointerException in Thread's run method

I would really appreciate help with my program. It is some sort of chat server with multiple clients.
Here's the server code:
package com.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static int PORT;
private ServerSocket server;
private Socket socket;
public Server(int port) throws IOException {
PORT = port;
server = new ServerSocket(PORT);
System.out.println("server started");
try {
while (true) {
socket = server.accept();
try {
new ServeClient(socket);
} catch (IOException e) {
socket.close();
}
}
} finally {
server.close();
}
}
public static void main(String[] args) throws IOException {
int port = Integer.parseInt(args[0]);
Server server = new Server(port);
}
}
I start the server and then create a Client. The server receives connection socket from socket
and creates a ServeClient Thread.
Here's ServeClient code:
package com.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;
import com.gui.WindowManager;
public class ServeClient extends Thread {
private final Socket socket;
private BufferedReader in;
private PrintWriter out;
private String msg;
public static final String ENDSTRING = "END";
public static Vector clients = new Vector();
public ServeClient(final Socket socket) throws IOException {
this.socket = socket;
System.out.println("socket " + socket);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
start();
}
public void run() {
try {
clients.add(this);
while (true) {
msg = in.readLine();
if (msg == ENDSTRING)
break;
broadcast(msg);
}
System.out.println("closing...");
} catch (IOException e) {
System.err.println("IO EXCEPTION");
} finally {
try {
socket.close();
} catch (IOException e) {
System.err.println("SOCKET NOT CLOSED");
}
}
}
#SuppressWarnings("deprecation")
public void broadcast(String msg) {
synchronized (clients) {
Enumeration<ServeClient> e = clients.elements();
while (e.hasMoreElements()) {
ServeClient serveClient = e.nextElement();
try {
synchronized (serveClient.out) {
serveClient.out.println(msg);
}
} catch (Exception eee) {
serveClient.stop();
}
}
}
}
}
What i get is a NullPointerException when ServeClient invokes run() method
server started
socket Socket[addr=/127.0.0.1,port=51438,localport=8888]
Exception in thread "Thread-0" java.lang.NullPointerException
at com.server.ServeClient.run(ServeClient.java:33)
line 33 is the line with first "try" statement in ServeClient run() method
com.server.ServeClient.run(ServeClient.java:33)
I don't believe that it's happening at the try.
Open up an IDE, turn on debugging, and step through until you can see what's happening. That's the fastest way to figure out what you've missed.
There's an object that you're assuming is fine that is not. Find it.
Here's an example of how to do this properly:
http://www.kodejava.org/examples/216.html
Your problem is with the order in which static instance variables are initialised. Try doing something like:
...
private static Vector clients = null;
...
if (clients==null) {
clients = new Vector(); // consider putting this in a synchronized block
}
before you add the client to the vector.
Sorry for necroing such an old issue but it seemed like this problem wasn't resolved, so I'll give a bit of input from my end.
I've had a similar problem and the compiler also kept telling me that the problem was at the start() method. However, when I commented out the thread part and just ran the code on the same thread as the UI, the compiler directed me to the real source of the problem: the code inside the thread.
After making sure the code didn't give an error, I enclosed the code with the original thread code, and it stopped giving me the NullPointerException error.
Hope this helps someone along the way.
Remove the duplicate class declaration in JPanel.
I was trying to run a timer thread that updated a clock in the main application window.
I had created the JFrame with Eclipse/WindowBuilder and had followed a tutorial on how to make a timer. I had copied the declaration of the textfield into the class declaration to make it available for the entire class, but forgot to remove the Class Id in front of the widget definition. So it still initialized the local instance and not the global one. Thus when I accessed the global one it was still null.

Categories

Resources