I am writing a simple encrypted instant messenger, which involves two projects: A server and client. I got these two working very well, but decided to add a prompt on the client side to ask for a server IP Address and port number. Upon the user pressing a button, I have added an action listener for it to create an instance of the instant messenger class, which extends JFrame.
When this is done from inside this action listener (or outside in a separate method, I have tried) it creates the client JFrame, but none of the components exist inside. The client connects to the server as normal.
When the client is created in the main method, however, the program works as normal.
Here, below, is the difference between what works and what will not work:
This does not work:
okay.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
try{
port = Integer.parseInt(portField.getText());
}catch(NumberFormatException e){
return;
}
serverIP = serverIPField.getText();
dispose();
Client c = new Client(serverIP, port);
c.startRunning();
}
});
However, this does work (same class):
public static void main(String args[]){
Client c = new Client(serverIP, port);
c.startRunning();
}
All I have done, is change where the Client class is created, from inside a class constructor (called Prompt, which creates a JFrame to ask for the IP and port) to the main method. I have tried creating an instance of the Client from a new class, with the main method in, which seems to work fine.
As I stated before, the JFrame is created and is opening fine, it even connectes successfully to the server, but none of the components exist (just a blank white area). This is strange as this is not the case when it is created inside the main method.
I have little idea as to why this is happening, so if somebody could explain why, that would be brilliant.
Thanks.
Edit: I appreciate that I may have not added enough information. Here is the Client constructor:
public Client(String host, int port){
super("Instant Messenger - Client");
this.port = port;
serverIP = host;
initComponents();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2);
setVisible(true);
keys = new EncryptionKeys(1024);
}
Start running method:
public void startRunning(){
try{
connectToServer();
setupStreams();
exchangeKeys();
whileChatting();
}catch(EOFException eofEx){
showMessage("\nClient Terminated connection");
}catch(IOException ioEx){
showMessage("\nCould not connect to server.");
}finally{
closeDown();
}
}
And the while chatting method that is called by startRunning():
private void whileChatting() throws IOException{
ableToType(true);
do{
try{
message = (String) input.readObject();
if(!keysSent){
if(message.substring(0, 1).equals("n")){
try{
keys.nForeign = new BigInteger(message.substring(1, message.length()));
}catch(NumberFormatException nfEx){
showMessage("Error sending keys");
}
}
else if(message.substring(0, 1).equals("e")){
try{
keys.eForeign = new BigInteger(message.substring(1, message.length()));
keysSent = true;
}catch(NumberFormatException nfEx){
showMessage("Error sending keys");
}
}
continue;
}
showEncryptedMessage(message);
}catch(ClassNotFoundException cnfEx){
showMessage("\nUser Sending error");
}
}while(!message.equals("SERVER - END"));
}
The dispose() closes the JFrame for the prompt to the user. The class Prompt is solely used to get information from the user regarding IP address and port, which is then closed, so that the Client can be opened.
All code to manage Swing components (eg painting, listeners, etc...) occurs on a single thread: the Event Dispatch Thread (EDT). The startRunning method calls whileChatting, which contains a do/while loop that doesn't immediatedly exit. What happens in the two Scenarios:
When the Client is created in main, it is created on the main Thread. This allows the while loop to operate on the Main thread, allowing the the EDT to run in parallel. (Note: you should create your GUI on the EDT using SwingUtilities)
When the Client is created on the EDT (in actionPerformed), the non-terminating loop will occur on the EDT, effectively locking it up and not allowing it to perform any tasks until it terminates (in other words, the components in the JFrame cannot paint, update, or react until the EDT is free)
If you wish to perform a long running task, then you should consider using a Thread.
Related
Basically, I'm creating a program that syncs HUE lights, and I'm having trouble incorporating the Listener that detects when the light bridge has been connected with my JavaFX GUI; I want it to switch a Label from "Not Connected" to "Connected" whenever the listener detects that it has connected.
Here's some pseudocode of how the program is structured.
public class MainClass extends Application {
boolean connected;
Label label;
public static void main(){
launch(args); //Neccesary to start JavaFX
}
public static void start(){
ConnectToHueLights(); //Takes abt 30s to connect to bridge
Label label = “Searching for connection”; //Message while connecting
Window.addLabel(); //Adds label to hue lights
Window.show(); //Makes window visible
}
private HueLightsListener(){
//Once connected, can do whatever inside of a void method inside of this Listener
private void onConnectionResponds(){
label = “Connected”
connected = true;
}
}
public void ConnectToHueLights(){
create new Listener();
}
Basically, the label doesn't change whenever the listener is active, and I'm not sure how to do that.
Thanks!
Use a suitable Worker to establish the connection to the bridge. Choose Task for a single unit of work; choose Service to manage multiple tasks. Use the task's updateMessage() method to notify the worker's message property listeners. You can pass a reference to the update method to your HueLightsListener, as shown here.
HueLightsListener listener = new HueLightsListener(this::updateMessage);
Your implementation of onConnectionResponds() can then tell the reference to accept() messages as needed.
public void onConnectionResponds() {
updater.accept("Connected");
…
}
As an aside, your implementation of call(), which runs in the background, can periodically poll the connection, while checking isCancelled(), and then send more commands once connected.
Im new to Android programming, my app is supposed create a socket in order to maintain constant contact with a server (get status and updates etc) while the user changes to different activities while using the app in general.
Im wondering how its possible for the user to change to different activity classes while still have a constant connection to the server.
I though maybe in main activity to create some background handler that always runs even if the player changes to a different activity.
That handler would be the entity that would maintain contact with the server, like a sort of background task, and also communicate status to show in whatever activity that happen to be running at the time.
something like
OnCreate(....)
{
handler=new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
tick();
handler.postDelayed(this,1000);
}
},1000);
}
void tick()
{
communicate with server
}
But what if the user changes to a different activity, does the handler still run? Can the socket still receive data from server even when a different activity is running if i set up some kind of socket call back that calls a function when it gets data, but that call back would be in the main activity, how can it get called if another activity is active?
Also how to communicate new information gotten from the socket to any activity that happens to be running as to update its UI. I would imagine having a data structure that all activities can access, that is populated by the thread or whatever is communicating with the server.
It seems pretty complicated, anybody have example or know the standard way to do it?
Thanks
This works for me, but I'm pretty sure there are better ways to keep the socket connection alive when changing activities, like using services(as I have read but not yet tried). You can have a look at an example of services here: Services Example
In my Main Activity (Where I create socket)
public static Socket socket;
public static Socket getSocket(){
return socket;
}
public static synchronized void setSocket(Socket socket){
MainActivity.socket = socket;
}
public class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
setSocket(socket);
if(socket!=null){
Intent goToNextActivity = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(goToNextActivity);
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
In my second activity, I just call it like this to use the same socket I created (for example)
MainActivity.getSocket().getOutputStream().write(String.valueOf(multiplier).getBytes());
Works well for me!
I have the following code in ServerConnectionManager:
public class ServerConnectionManager implements Runnable {
private DatagramPacket receivedPacket;
//some more things here
public ServerConnectionManager(DatagramPacket receivedPacket){
this.receivedPacket = receivedPacket;
System.out.println("Connection manager has been assigned a request");
System.out.println("The port of the request packet is "+receivedPacket.getPort());
try {
sendReceiveSocket = new DatagramSocket();
} catch (SocketException se) {
se.printStackTrace();
System.exit(1);
}
}
#Override
public void run() {
//DEBUGGING LINES HERE
System.out.println("The start method on connection manager works..");
System.out.println("Point A");
System.out.println("The port of the request packet is "+receivedPacket.getPort()); // the thread gets stuck here
System.out.println("Does this work..?"); //This line never gets printed
//some other stuff to be done here
}
}
And i have some code in the run method of some other threads that make use of ServerConnectionManager: Lets Call this Thread B
#Override
public void run() {
while(true){
try {
System.out.println("Waiting..."); // so we know we're waiting
receiveSocket.receive(receivePacket);
} catch (IOException e) {
System.out.print("Stopped Listening for some reason..");
//e.printStackTrace();
}
System.out.println("Server received something" );
//Constructor of ServerConnectionManager
ServerConnectionManager serverConnectionManager = new ServerConnectionManager(receivePacket);
Thread managerThread = new Thread(serverConnectionManager, "connectionManager ");
managerThread.start();
//some more stuff to be done
}
}
The problem is that I can not call any methods on receivedPacket from within ServerConnectionManager run method. However, I am able to call receivedPacket.getPort() from within the constructor of this ServerConnectionManager thread and it gives me an expected output. But it does not do anything from within run method. The last line ServerConnectionManager prints is "Point A". Nothing after that!! Please check my DEBUGGING comments around that area to get a better idea of what I am talking about.
I know I have provided alot of code. But I can not understand the problem at all. I have tried passing additional parameters(objects) from Thread B to the constructor of ServerConnectionManager. And I am able to access those from the run method of ServerConnectionManager. Its just the receivedPacket that does not work...
You need to create a new DatagramPacket per receive if you want to start a new thread to handle it. Otherwise one thread is synchronized on it during receive() while the other thread is trying to call getPort(). The design is invalid in any case, as the receive() will overwrite everything in the previously received datagram while the thread is trying to process it.
Following is the code to input proxy settings from user.
public static void setProxy()
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new proxy().setVisible(true);
}
});
// Control should halt here till user gives input as it assigns value to the variables
String host = prox;
String port = prt;
System.out.println("Using proxy: " + host + ":" + port);
You're not doing it correctly. The main method of a GUI application should do only one thing: start the GUI. The rest of the logic will be triggered by events fired by the user interacting with the GUI.
So, assuming your GUI displays a frame containing 2 text fields to enter the host and the port and a button to proceed, you should have, in your GUI, an action listener on the button:
proceedButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String host = hostTextField.getText();
String port = portTextField.getText();
doSomethingWithHostAndPort(host, port);
}
});
If doSomethingWithHostAndPort() does domething long, then it should do it in a separate thread, to avoid freezing the GUI.
You need to provide more information if you want a precise answer. But I'm going to make a few assumptions, you have a button which is pressed after information is entered, that button has an on click event attached to it, that is where you add your variable assignments and start the processing.
I have a JFrame that I call mainFrame, it is the main JFrame shown to the user when using my program.
The program creates a Socket to a server and sends messages back and fourth between it and the server.
I am attempting to create a Thread to handle the connection. So when a user clicks "connect" the Thread will setup the Socket and associated input and output streams. I then want the Thread to wait until the JFrame sends it a command, the command just being a String that it should print to the output stream of the Socket. The Thread will send the command, read the response, and then wait for another command.
I figure I could setup a queue that I can "deposit" commands into it and then when the Thread gets around to it, it can pull the first command off of the queue and do with it as it pleases.
Any ideas how to go about that?
Also, currently I pass the argument this to the Thread so that it can access a function in the JFrame to print output to a text area. Is this ok to do? Can I allow the Thread to call methods in the JFrame which spawned it?
Suggestions:
The Swing GUI can send text to the Socket, and I don't believe that any additional thread is needed for this since this is non-blocking.
Yes a separate thread is needed to wait on the Socket and read incoming data. You could use a Scanner perhaps or BufferedReader for this purpose.
Then send the text from this thread to the GUI perhaps when any new-line chars are encountered. This will need to be done on the EDT, perhaps via the publish/process method pair of a SwingWorker, vs a PropertyChangeListener.
and yes, a background thread can call methods on the GUI, but always take care to do this on the Swing event thread by placing the code in a Runnable and queuing it on the Swing event queue via SwingUtilities.invokeLater(...).
Edit
You comment:
What does "on the EDT" mean?
EDT = the Swing Event Dispatch Thread, the main Swing thread that performs all Swing drawing and user interactions. If you block this thread, you block all of Swing's display and UI, essentially freezing your program. For details, please see Concurrency in Swing.
Also say that sending text to the socket was blocking, how might I setup a command queue for it?
I don't understand this question since sending information on the socket shouldn't be blocking as far as I understand things.
See this code, but you must implement the parameters yourself:
public class ConnectionThread extends Thread {
public static final HOST = "www.example.com";
public static final PORT = 24239;
private String command;
private boolean lookahead = false;
private boolean allowChangeLookahead = true;
private boolean canRetrieveResult = false;
Private String result;
orivate Socket s = new Socket(HOST, PORT);
public void run() {
for(;;) { // Infinite loop
sleep(500); // Avoid low perfomance related problems.
if(lookahead) {
allowChangeLookahead = false;
try {
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out.println(command);
result = in.readLine();
canRetrieveResult = true;
} catch(Exception e) {
// Something occured...
}
lookahead = false;
allowChangeLookAhead = true;
}
}
}
public synchronized void command(String cmd) {
command = cmd;
for(;;) { // Don't worry, not infinite
if(allowChangeLookahead) {
lookahead = true;
break;
}
}
}
public synchronized String getResult() {
for(;;) {
if(canRetrieveResult) {
return result;
}
}
}
}
Meanwhile, in main sequence...
ConnectionThread conThread = new ConnectionThread();
conThread.start();
// ...
// Code of method that responds to command
if(calledCommand) {
conThread.command(theCommand);
result = conThread.getResult();
}
That's it! And remember to write the server, ask me if you want help.