im writing a multithread chat program where i hope to have a server connected to multiple clients, the clients can talk to each and send messages to each other. I want all messages from the clients to be visible to the server, moreover that the server can send messages to all visible clients. My program only connects the server to one client and they can send messages.
package chatserver2;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
// import all the class that you will need for functionailty
// extends jframe to develop gui's in java
public class Server2 {
private static JTextField userInput; //
private static JTextArea theChatWindow; //
private static ObjectOutputStream output; // stream data out
private static ObjectInputStream input; // stream data in
private static ServerSocket server;
private static Socket connection; // socket means set up connetion between 2 computers
private static JFrame frame;
private static int n;
//Constructor
public static void main(String[] args) throws IOException {
Server2 obj = new Server2();
// Socket sock=new Socket("localhost",6789);
System.out.println("Hello 4");
obj.RunServer();
System.out.println("Hello 3");
try {
while (true) {
System.out.println("Hello 2");
Handler obj2 = new Handler();
//Handler obj3=new Handler();
obj2.start();
System.out.println("Accepted connection from "
+ connection.getInetAddress() + " at port "
+ connection.getPort());
n++;
System.out.println("Count " + n);
}
} finally {
connection.close();
}
}
public Server2() {
frame = new JFrame();
userInput = new JTextField();
userInput.setEditable(false); // set this false so you dont send messages when noone is available to chat
// action event listener to check when the user hits enter for example
userInput.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
sendMessage(event.getActionCommand()); // string entered in the textfield
userInput.setText(""); // reset text area to blank again
}
}
);
// create the chat window
frame.add(userInput, BorderLayout.NORTH);
theChatWindow = new JTextArea();
frame.add(new JScrollPane(theChatWindow));
frame.setSize(300, 150);
frame.setVisible(true);
}
// run the server after gui created
public void RunServer() {
try {
server = new ServerSocket(6789); // 1st number is port number where the application is located on the server, 2nd number is the amount of people aloud to connect
while (true) {
try {
waitForConnection(); // wait for a connection between 2 computers
setupStreams(); // set up a stream connection between 2 computers to communicate
whileChatting(); // send message to each other
// connect with someone and have a conversation
} catch (EOFException eofException) {
showMessage("\n Server ended Connection");
}
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
//Wait for a connection then display connection information
private void waitForConnection() {
showMessage("waiting for someone to connect to chat room....\n");
try {
connection = server.accept();
} catch (IOException ioexception) {
ioexception.printStackTrace();
}
showMessage("Now connected to" + connection.getInetAddress().getHostName());
showMessage(" at port " + connection.getPort());
}
// stream function to send and recive data
private void setupStreams() throws IOException {
output = new ObjectOutputStream(connection.getOutputStream()); // set up pathway to send data out
output.flush(); // move data away from your machine
input = new ObjectInputStream(connection.getInputStream()); // set up pathway to allow data in
// String message = "WAIT";
// sendMessage(message);
//showMessage("\n Connection streams are now setup \n");
}
// this code while run during chat conversions
private void whileChatting() throws IOException {
String message = "WAIT ";
sendMessage(message);
allowTyping(true); // allow user to type when connection
do {
// have conversion while the client does not type end
try {
message = (String) input.readObject(); // stores input object message in a string variable
showMessage("\n " + message);
System.out.println("Message from Client " + message);
} catch (ClassNotFoundException classnotfoundException) {
showMessage("\n i dont not what the user has sent");
}
} while (!message.equals("CLIENT - END"));// if user types end program stops
}
private void closeChat() {
showMessage("\n closing connections...\n");
allowTyping(true);
try {
output.close(); // close output stream
input.close(); // close input stream
connection.close(); // close the main socket connection
} catch (IOException ioexception) {
ioexception.printStackTrace();
}
}
// send message to the client
private void sendMessage(String message) {
try {
output.writeObject(message);
output.flush(); // send all data out
showMessage("\nServer - " + message);
System.out.println("Message to client " + message);
} catch (IOException ioexception) {
theChatWindow.append("\n ERROR: Message cant send");
}
}
// update the chat window (GUI)
private void showMessage(final String text) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
theChatWindow.append(text);
}
}
);
}
// let the user type messages in their chat window
private void allowTyping(final boolean trueOrFalse) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
userInput.setEditable(trueOrFalse);
}
}
);
}
public static class Handler extends Thread {
private Socket connection;
// static private ServerSocket server;
public Handler() {
// this.socket = socket;
String message = "WAIT";
}
//connection = server.accept();
public void run() {
System.out.println("Connect" + Server2.connection);
while (true) {
try {
waitForConnection();
setupStreams();
whileChatting();
} catch (IOException ex) {
Logger.getLogger(Server2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private void waitForConnection() {
System.out.println("Heelo");
showMessage("waiting for someone to connect to chat room....\n");
System.out.println("server" + server);
try {
connection = server.accept();
} catch (IOException ioexception) {
ioexception.printStackTrace();
}
System.out.println("Connection" + connection);
showMessage("Now connected to" + connection.getInetAddress().getHostName());
showMessage("AT port" + connection.getPort());
}
private void setupStreams() throws IOException {
output = new ObjectOutputStream(connection.getOutputStream()); // set up pathway to send data out
output.flush(); // move data away from your machine
input = new ObjectInputStream(connection.getInputStream()); // set up pathway to allow data in
showMessage("\n Connection streams are now setup \n");
}
// this code while run during chat conversions
private void whileChatting() throws IOException {
String message = " You are now connected ";
sendMessage(message);
allowTyping(true); // allow user to type when connection
do {
// have conversion while the client does not type end
try {
message = (String) input.readObject(); // stores input object message in a string variable
showMessage("\n " + message);
} catch (ClassNotFoundException classnotfoundException) {
showMessage("\n i dont not what the user has sent");
}
} while (!message.equals("CLIENT - END"));// if user types end program stops
}
private void closeChat() {
showMessage("\n closing connections...\n");
allowTyping(true);
try {
output.close(); // close output stream
input.close(); // close input stream
connection.close(); // close the main socket connection
} catch (IOException ioexception) {
ioexception.printStackTrace();
}
}
// send message to the client
static private void sendMessage(String message) {
try {
output.writeObject(message);
output.flush(); // send all data out
showMessage("\nServer - " + message);
} catch (IOException ioexception) {
theChatWindow.append("\n ERROR: Message cant send");
}
}
// update the chat window (GUI)
static private void showMessage(final String text) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
theChatWindow.append(text);
}
}
);
}
// let the user type messages in their chat window
private void allowTyping(final boolean trueOrFalse) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
userInput.setEditable(trueOrFalse);
}
}
);
}
}
}
Here is the client :
package chatserver2;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// import all the class that you will need for functionailty
// extends jframe to develop gui's in java
public class Client2 extends JFrame {
private JTextField userInput; //
private JTextArea theChatWindow; //
private ObjectOutputStream output; // stream data out
private ObjectInputStream input; // stream data in
private Socket connection; // socket means set up connetion between 2 computers
//Constructor
public Client2() {
super("My Chat Service");
userInput = new JTextField();
userInput.setEditable(false); // set this false so you dont send messages when noone is available to chat
// action event listener to check when the user hits enter for example
userInput.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
sendMessage(event.getActionCommand()); // string entered in the textfield
userInput.setText(""); // reset text area to blank again
}
}
);
// create the chat window
add(userInput, BorderLayout.NORTH);
theChatWindow = new JTextArea();
add(new JScrollPane(theChatWindow));
setSize(300, 150);
setVisible(true);
}
// run the server after gui created
public void RunServer() {
try {
connection = new Socket("localhost", 6789);// 1st number is port number where the application is located on the server, 2nd number is the amount of people aloud to connect
while (true) {
try {
// wait for a connection between 2 computers
setupStreams(); // set up a stream connection between 2 computers to communicate
whileChatting(); // send message to each other
// connect with someone and have a conversation
} catch (EOFException eofException) {
showMessage("\n Server ended Connection");
} finally {
closeChat();
}
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
//Wait for a connection then display connection information
// stream function to send and recive data
private void setupStreams() throws IOException {
output = new ObjectOutputStream(connection.getOutputStream()); // set up pathway to send data out
output.flush(); // move data away from your machine
input = new ObjectInputStream(connection.getInputStream()); // set up pathway to allow data in
showMessage("\n Connection streams are now setup \n");
}
// this code while run during chat conversions
private void whileChatting() throws IOException {
String message = "";
allowTyping(true); // allow user to type when connection
do {
// have conversion while the client does not type end
try {
message = (String) input.readObject(); // stores input object message in a string variable
System.out.println("message " + message);
if (message.equals("WAIT")) {
ServerSocket server2 = new ServerSocket(5000);
System.out.println("Hello");
message = "5000";
sendMessage(message);
}
System.out.println("From server " + message);
showMessage("\n " + message);
} catch (ClassNotFoundException classnotfoundException) {
showMessage("\n i dont not what the user has sent");
}
} while (!message.equals("CLIENT - END"));// if user types end program stops
}
private void closeChat() {
showMessage("\n closing connections...\n");
allowTyping(true);
try {
output.close(); // close output stream
input.close(); // close input stream
connection.close(); // close the main socket connection
} catch (IOException ioexception) {
ioexception.printStackTrace();
}
}
// send message to the client
private void sendMessage(String message) {
try {
output.writeObject(" - " + message);
output.flush(); // send all data out
showMessage("\nServer - " + message);
} catch (IOException ioexception) {
theChatWindow.append("\n ERROR: Message cant send");
}
}
// update the chat window (GUI)
private void showMessage(final String text) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
theChatWindow.append(text);
}
}
);
}
// let the user type messages in their chat window
private void allowTyping(final boolean trueOrFalse) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
userInput.setEditable(trueOrFalse);
}
}
);
}
public static void main(String[] args) {
Client2 obj = new Client2();
obj.RunServer();
}
}
Related
This has been the method so far to send and receive on bluetooth using Java with threading. But how do we do this using Kotlin's latest Coroutines? Alot of this old Java cold no longer translates to Kotlin 1.4+ either in terms of how to do threading. I read Kotlin is now using Coroutines instead of threads like before.
public class MainActivity extends AppCompatActivity {
private static final UUID MY_UUID_INSECURE =
UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")
public void pairDevice(View v) {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
Object[] devices = pairedDevices.toArray();
BluetoothDevice device = (BluetoothDevice) devices[0]
ConnectThread connect = new ConnectThread(device,MY_UUID_INSECURE);
connect.start();
}
}
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket;
public ConnectThread(BluetoothDevice device, UUID uuid) {
mmDevice = device;
deviceUUID = uuid;
}
public void run(){
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = mmDevice.createRfcommSocketToServiceRecord(MY_UUID_INSECURE);
} catch (IOException e) {
}
mmSocket = tmp;
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
} catch (IOException e1) {
}
}
//will talk about this in the 3rd video
connected(mmSocket);
}
}
private void connected(BluetoothSocket mmSocket) {
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = mmSocket.getInputStream();
tmpOut = mmSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(buffer);
final String incomingMessage = new String(buffer, 0, bytes);
runOnUiThread(new Runnable() {
#Override
public void run() {
view_data.setText(incomingMessage);
}
});
} catch (IOException e) {
Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage() );
break;
}
}
}
public void write(byte[] bytes) {
String text = new String(bytes, Charset.defaultCharset());
Log.d(TAG, "write: Writing to outputstream: " + text);
try {
mmOutStream.write(bytes);
} catch (IOException e) {
}
}
}
public void SendMessage(View v) {
byte[] bytes = send_data.getText().toString().getBytes(Charset.defaultCharset());
mConnectedThread.write(bytes);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
send_data =(EditText) findViewById(R.id.editText);
view_data = (TextView) findViewById(R.id.textView);
if (bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
public void Start_Server(View view) {
AcceptThread accept = new AcceptThread();
accept.start();
}
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread(){
BluetoothServerSocket tmp = null ;
try{
tmp = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("appname", MY_UUID_INSECURE);
}catch (IOException e){
}
mmServerSocket = tmp;
}
public void run(){
Log.d(TAG, "run: AcceptThread Running.");
BluetoothSocket socket = null;
try{
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
}catch (IOException e){
}
//talk about this is in the 3rd
if(socket != null){
connected(socket);
}
}
}
I have a really simple multithreaded server as attached.
When my client calls the server, the server gives below exception:
java.net.SocketException: Socket is closed
but my code did not close the socket.
The first code segment is my client. The second and third code segments define the server and the way it handles requests. I had another single-threaded client-server and it worked properly.
Could somebody help take a look?
public class SocketClient {
public static void main(String[] args) {
String hostname = "127.0.0.1";
int port = 900;
try{
Socket socket = new Socket(hostname, port);
OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true);
writer.println("GET /");
writer.println();
writer.flush();
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
}
}
public class SimpleHTTPServer {
public static void main(String[] args) throws Exception {
//create a network socket which can accept connection on certain TCP port
//create Server which can accept requests
final ServerSocket server = new ServerSocket(900);
System.out.println("Listening for connection on port 900...");
while(true) {
try (Socket socket = server.accept()) { //creates socket when new request is received
System.out.println("received request");
RequestHandler rh = new RequestHandler(socket); //RequestHandler implements runnable interface, pass this object to create Thread
Thread thread = new Thread(rh);
thread.start(); //begins run() method defined in rh
}
}
}
}
public class RequestHandler implements Runnable {
private Socket socket;
public RequestHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
System.out.println("calling handleRequest");
handleRequest();
} catch (Exception e) {
System.err.println(e);
try {
socket.close();
} catch (IOException e1) {
System.err.println("Error Closing socket connection");
System.exit(0);
}
}
}
private void handleRequest() throws Exception {
System.out.println("handleRequest called");
Date today = new Date();
String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
System.out.println("1st" + httpResponse);
socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
System.out.println("2nd" + httpResponse);
System.out.println("got a new request");
}
}
I changed the server to below and it works-
public class SimpleHTTPServer {
public static void main(String[] args) throws Exception {
//create a network socket which can accept connection on certain TCP port
//create Server which can accept requests
final ServerSocket server = new ServerSocket(900);
System.out.println("Listening for connection on port 900...");
while(true) {
try { //creates socket when new request is received
Socket socket = server.accept();
System.out.println("received request");
RequestHandler rh = new RequestHandler(socket); //RequestHandler implements runnable interface, pass this object to create Thread
Thread thread = new Thread(rh);
thread.start(); //begins run() method defined in rh
// Date today = new Date();
// String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
// socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
// System.out.println("got a new request");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Can someone please provide example code on how to use the Bluetooth cn1 library to read and write text data? I tried looking through the project source code (https://github.com/chen-fishbein/bluetoothle-codenameone) for example code, but could not find any that reads/writes text data using the appropriate methods. Those methods also don't have any Java docs.
Here's the code I'm using to send:
public void sendMessage(String message) {
if (Display.getInstance().isSimulator()) {
System.out.println(message);
} else {
// System.out.println("Sending message: " + message);
String b64WriteString = Base64.encode(message.getBytes());
try {
bt.write(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
}
}, deviceAddress, services.get(0), sendDataCharacteristic, b64WriteString, false);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
And here to receive:
private void registerNotifications() {
System.out.print("Registering notifications...");
try {
bt.subscribe(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
JSONObject dataIncoming = (JSONObject) evt.getSource();
String base64Value = "";
try {
if (dataIncoming.getString("status").equals("subscribedResult")) {
base64Value = dataIncoming.getString("value");
}
} catch (JSONException e) {
e.printStackTrace();
}
String message = new String(Base64.decode(base64Value.getBytes()));
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
messageReceived.set(message);
}
});
}
}, deviceAddress, services.get(0), receiveDataCharacteristic);
System.out.println("Registered");
System.out.println("Starting communication");
} catch (IOException e) {
System.err.println("Unable to register notifications " + e.getMessage());
e.printStackTrace();
}
}
I have fields defined for the service and characteristic UUID's. Also, the callSerially might not be needed anymore. I think I recall that the CN1LIB was updated to do that, but I don't remember for certain.
For that device, the service characteristic is "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
The sendCharacteristic is "0x0002"
The receiveCharacteristic is "0x0003"
After taking the suggestions of James H, and some more trial an error, I finally manage to get data transfer between the Adafruit's Bluefruit LE Friend working consistently, at least on an Android device. Not sure about iOS though, since I haven't tested it. Here are the critical code pieces needed.
First, you need the Service, TX and RX Characteristics UUIDs. These UUIDs were found here. Note, these don't need to be upper case.
public static final String UUID_SERVICE = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
public static final String UUID_RX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
public static final String UUID_TX = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
Next, once you scanned and found the devices, call the connect() method to make the actual connection, and critically call the discover() method. Once the discover() callback gets called, then add the "subscriber" to receive data.
private void connect(String address) {
bleAddress = address; // set the global BLE address
if (!connected) {
// start an infinite progress dialog
final Dialog ip = new InfiniteProgress().showInifiniteBlocking();
try {
bt.connect(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
ip.dispose();
Object obj = evt.getSource();
print("Connected to Bluetooth LE device ...\n" + obj, true);
// must be called on Android devices in order to load on the UUIDs, otherwise there is an error that service can't be found. Won't do anything on ios though?
discover();
connected = true;
}
}, address);
} catch (IOException ex) {
ip.dispose();
String message = "Error connecting to bluetooth device: " + address;
print(message + "\n" + ex.getMessage(), false);
}
} else {
String message = "BLE device already connected to: " + address;
print(message, false);
}
}
private void discover() {
try {
bt.discover(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
print("BLE Information Received ...", true);
addSubscriber();
}
}, bleAddress);
} catch (Exception ex) {
print(ex.getMessage(), false);
}
// if we running on is add the subscriber here since the above bt call
// does nothing?
if (Display.getInstance().getPlatformName().equals("ios")) {
print("Adding subscriber for iOS Device", true);
addSubscriber();
}
}
private void addSubscriber() {
try {
bt.subscribe(new ActionListener() {
StringBuilder sb = new StringBuilder();
#Override
public void actionPerformed(ActionEvent evt) {
JSONObject dataIncoming = (JSONObject) evt.getSource();
String base64Value = "";
try {
if (dataIncoming.getString("status").equals("subscribedResult")) {
base64Value = dataIncoming.getString("value");
}
} catch (JSONException e) {
console.setText("Error reading data: " + e.getMessage());
}
String message = new String(Base64.decode(base64Value.getBytes()));
sb.append(message);
if (message.endsWith("\r\n")) {
processData(sb.toString());
sb = new StringBuilder();
}
}
}, bleAddress, UUID_SERVICE, UUID_RX);
String message = console.getText() + "\nSubcriber added ...";
console.setText(message);
} catch (IOException ex) {
String message = "Error Subscribing: " + ex.getMessage();
console.setText(message);
}
}
So this sets up the connection, discovers the services, and finally adds the subscriber method which receives the data, and critically uses a buffer to collect the received data until the CRLF characters are received.
However, another major issue I ran into was the default 23 byte send limit (maybe an Android only issue?) of the BLE specification. If you tried sending more than this, the connection just gets dropped with no meaningful error message being returned. To get around this, I used the technique suggested here, which entails splitting data into chunks of 20 byte arrays. Since we sending regular ASCII text, then 20 characters should be 20 bytes, so I just split the text into Strings 20 characters long. Not the most efficient by it works and it easier to debug.
private void sendText(final String data) {
try {
String b64String = Base64.encode(data.getBytes());
bt.write(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if(data.endsWith("\r\n")) {
print("Data sent ...", true);
}
}
}, bleAddress, UUID_SERVICE, UUID_TX, b64String, false);
} catch (IOException ex) {
String message = "Error sending: " + data + "\n"
+ UUID_SERVICE + "\n"
+ UUID_TX + "\n"
+ ex.getMessage();
print(message, false);
}
}
private void splitAndSend(String text) {
text += "\r\n";
// first split data in chunk size of 20 chracters
ArrayList<String> sl = new ArrayList<>();
char[] data = text.toCharArray();
int len = data.length;
int chunkSize = 20;
for (int i=0; i < len; i+= chunkSize) {
sl.add(new String(data, i, Math.min(chunkSize,len - i)));
}
// now send chunks amd wait 100 ms to prevent any erros
for(String word: sl) {
sendText(word);
try {
Thread.sleep(100);
} catch (InterruptedException ex) {}
}
}
The complete source code with GUI stuff can be found here, but this is definitely a work in progress.
I am having trouble coding the socket side of a JavaFX chat client. This is my first time having to deal with socket in any sort of way, so some trouble was expected. I've been following this page to design the server-client side:
http://pirate.shu.edu/~wachsmut/Teaching/CSAS2214/Virtual/Lectures/chat-client-server.html
My problem is getting text I enter into the GUI into a DataInputSteam and DataOutputStream so that others on the same server can see the changes. I do
not understand how to convert the text in the UI to something the sockets
can work with.
Here is part of my controller class:
#FXML
private TextArea messageArea;
#FXML
private Button sendButton;
private ChatClient client;
#FXML
public void initialize() {
client = new ChatClient(ChatServer.HOSTNAME, ChatServer.PORT);
sendButton.setOnAction(event -> {
client.handle(messageArea.getText());
});
}
The ChatClient class is a Runnable with a DataInputStream and DataOutputStream field that connects to a Socket. I haven't changed much from the link:
public class ChatClient implements Runnable {
private Socket socket;
private Thread thread;
private DataInputStream streamIn;
private DataOutputStream streamOut;
private ChatClientThread client;
public ChatClient(String serverName, int port) {
System.out.println("Establishing connection...");
try {
socket = new Socket(serverName, port);
System.out.println("Connected: " + socket);
start();
} catch (UnknownHostException e) {
System.out.println("Unknown host: " + e.getMessage());
} catch (IOException e) {
System.out.println("Unexpected: " + e.getMessage());
}
}
#Override
public void run() {
while (thread != null) {
try {
streamOut.writeUTF(streamIn.readUTF());
streamOut.flush();
} catch (IOException e) {
System.out.println("Sending error: " + e.getMessage());
stop();
}
}
}
public void handle(String msg) {
try {
streamOut.writeUTF(msg);
streamOut.flush();
} catch (IOException e) {
System.out.println("Could not handle message: " + e.getMessage());
}
System.out.println(msg);
}
public void start() throws IOException {
streamIn = new DataInputStream(socket.getInputStream());
streamOut = new DataOutputStream(socket.getOutputStream());
if (thread == null) {
client = new ChatClientThread(this, socket);
thread = new Thread(this);
thread.start();
}
}
So in the controller class, I am calling the handle method which deals with the streams. The original code just wrote to the console, so I had to change the line:
streamIn = new DataInputStream(System.in)
to
streamIn = new DataInputStream(socket.getInputStream());
There is also a ChatClientThread class that extends Thread and just calls ChatClient.handle() in its run method.
I guess my question is how to update a GUI whenever writeUTF and readUTF interact with the DataStreams. I understand that streamOut.writeUTF(msg) changes the DataOutputStream to "have" that string, but I'm not sure how I'm supposed to use that datastream to update my gui so that all clients using the application can see the update. The way I have it now, if I run two instances of the JavaFX app, they dont' communicate through the UI or the console. My program just stalls whenever I click the send button
I have a client/server app to manage a line of some sort.
all the clients add objects to my line.
I want the server to send a screen capture of the jpanel to the clients every time there is a change in the line, line inserted or removed.
I managed to capture the jpanel to a jpeg and even send it.
but the flow of my app is stopped, after the first update I get eofexception that terminates my listening server socket.
what is the correct way to update a client ? should I set a serversocket to always listen on the client side too ?
please help, im stuck with this for like 2 weeks.
This is my listening thread (Server):
public class ListeningThread implements Runnable {
static boolean listening = true;
public BufferedReader in;
public void run() {
ServerSocket echoServer = null;
String line;
DataInputStream is = null;
PrintStream os = null;
Socket clientSocket = null;
try {
echoServer = new ServerSocket(RequestReciever._communicationPort);
}
catch (IOException e) {
System.out.println(e);
}
// Create a socket object from the ServerSocket to listen and accept
// connections.
// Open input and output streams
try {
// As long as we receive data, send it to be phrased to a request.
while (true) {
clientSocket = echoServer.accept();
is = new DataInputStream(clientSocket.getInputStream());
os = new PrintStream(clientSocket.getOutputStream());
// An option for a stop listening button. currently not available !
if( listening==true ) {
line = is.readUTF();
os.println(line);
System.out.println(line);
RequestReciever.pharseToRequest(line);
// clientSocket = null;
}
else {
echoServer.close();
is.close();
os.close();
break;
}
}
}
catch (IOException e) {
e.printStackTrace();
System.out.println("Listening Thread Unknown error");
}
}
}
This is my Pharse Method:
public static void pharseToRequest(String input) {
List<String> list = new ArrayList<String>(Arrays.asList(input.split(";;;")));
if (list.get(0).equalsIgnoreCase("Login") && list.get(1).equalsIgnoreCase ("Login") && list.get(2).equalsIgnoreCase("5"))
{
_adminClients.add(list.get(4));
updateScreenCapture();
AdminClientUpdate tmp = new AdminClientUpdate(list.get(4));
Thread aCU = new Thread (tmp);
aCU.start();
}
else
{
ServerRequest newReq = new ServerRequest(list.get(0), list.get(1), Integer.parseInt(list.get(2)),list.get(3),list.get(4));
addRequest(newReq);
}
}
and This is the AdminClientUpdate Class
public class AdminClientUpdate implements Runnable {
static boolean listening = true;
public BufferedReader in;
public String _ip;
public AdminClientUpdate(String ip)
{
_ip = ip;
}
public void run() {
try {
Socket socket = new Socket(_ip, RequestReciever._communicationPort);
InputStream in = new FileInputStream("Capture/tmp.jpg");
java.io.OutputStream out = socket.getOutputStream();
copy(in, out);
System.out.println("Sent Image !");
socket.close();
out.close();
in.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
System.out.println("Cant find tmp.jpg");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static void copy(InputStream in, java.io.OutputStream out) throws IOException {
byte[] buf = new byte[8192];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
eliminate this
echoServer.close();
this line closes the socket. due which the connection is aborted.
After a few brain meltdowns , I have decided that putting a server socket on the client side to listen for updates from the server is the best way.
I fixed a few things :
* The server should start a new thread to handle every accepted connection, instead of processing each one in-line in the accept thread.
* I tried to get the first update via the server socket instead of the login initialization.
now, after getting the 1st update while logging in, I added a Server Socket on the client side so it will keep listening for further updates from server.