Chat with Socket and RxJava - java

I'm creating this chat application where the users can talk when they're connected on same WiFi. They detect each others using Network Service Discovery (it works very bad, sometimes they doesn't find each other). Once they have seen each other on the network they can start a conversation. I'd created this class:
code:
public class ChatConnection {
private ServerSocket serverSocket;
private Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
private DataInputStream dataInputStream;
private DataOutputStream dataOutputStream;
private String message = "";
private Thread serverThread;
#Inject
public ChatConnection() {
serverThread = new Thread(new ServerThread());
serverThread.start();
}
public Observable<Boolean> connectToServer(InetAddress host, int port)
{
return Observable.unsafeCreate(new Observable.OnSubscribe<Boolean>() {
#Override
public void call(Subscriber<? super Boolean> subscriber) {
try {
if (socket != null) {
if (socket.isConnected()) {
socket.close();
}
socket = new Socket(host, port);
} else
socket = new Socket(host, port);
subscriber.onNext(socket.isConnected());
} catch (IOException e) {
subscriber.onError(e);
}
}
});
}
public Observable<String> observeServer() {
return Observable.unsafeCreate(new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
try {
while (!message.equals("##exit##")) {
message = dataInputStream.readUTF();
subscriber.onNext(message);
}
} catch (IOException e) {
subscriber.onError(e);
}
});
}
public Observable<Boolean> sendMessage(String message) {
return Observable.unsafeCreate(new Observable.OnSubscribe<Boolean>() {
#Override
public void call(Subscriber<? super Boolean> subscriber) {
try {
dataOutputStream.writeUTF(message);
subscriber.onNext(true);
} catch (IOException e) {
subscriber.onError(e);
}
}
});
}
public int getLocalPort() {
return serverSocket.getLocalPort();
}
public void tearDown() {
try {
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerThread implements Runnable {
#Override
public void run() {
try {
serverSocket = new ServerSocket(0);
socket = serverSocket.accept();
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
dataInputStream = new DataInputStream(inputStream);
dataOutputStream = new DataOutputStream(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The problem is observeServer() is not doing anything, even setting Log.d(...) inside never shows anything. I'm very new with java sockets. I would like someone tells me what I'm doing wrong. Thank you.

Related

Android client/server application - proper way to receive messages continously

I'm trying to make a client/server application using an Android phone as a client using AsyncTask to send messages from UI.
I've written some very basic implementation just to test the connection and the way that messages are received / sent and I found a very big problem.
The client part seems to work fine..from my perspective. But the server part is the problem. I can't make the server reading and displaying messages countinously from the client.
I tried something like while(line = (in.readLine()) != null) {} but it doesn't seems to work.
After I sent my first word from the client, the server reads null and it stops.
Can someone show me a proper way to keep the server running while the client is not sending nothing?
I'd like to avoid using while(true) if it's not 100% necessary.
Here is the implementation until now:
Server:
public class SocketServerThread extends Thread {
private static final Logger log = Logger.getLogger(SocketServerThread.class);
private static final int SERVER_PORT_NUMBER = 5000;
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(SERVER_PORT_NUMBER);
serverSocket.setReuseAddress(true);
log.info("Waiting for connection...");
Socket clientSocket = serverSocket.accept();
log.info("Connected! Receiving message...");
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
try {
while (true) {
String line = in.readLine();
if (line != null) {
log.info(line);
}
}
} catch (Exception e) {
log.error("Unexpected exception while sending / receiving messages.");
e.printStackTrace();
} finally {
in.close();
clientSocket.close();
serverSocket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Client:
public class MyAsyncTask extends AsyncTask<String, Integer, String> {
private static final String TAG = "MyAsyncTask";
private static final String SERVER_IP_ADDRESS = "10.0.2.2";
private static final int SERVER_PORT_NUMBER = 5000;
private PrintWriter out;
#Override
protected String doInBackground(String... params) {
String message = "";
try {
InetAddress address = InetAddress.getByName(SERVER_IP_ADDRESS);
Log.d(TAG, "Connecting...");
Socket socket = new Socket(address, SERVER_PORT_NUMBER);
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
Log.d(TAG, "I/O created");
message = params[0];
if (!message.equals("stop")) {
sendMessage(message);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
out.flush();
out.close();
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return message;
}
private void sendMessage(String message) {
if (out != null && !out.checkError()) {
out.println(message);
out.flush();
Log.d(TAG, "Sent message: " + message);
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.d(TAG, "onPostExecute(), s: " + s);
}
Thank you.
The problem is that your BufferedReader only read the first input stream. In order to receive the text after that, you have to re-read the input stream. I do it by recreating the socket when I am done reading, so that I can read next coming data. I am using the following code in my app. You can use this
private ServerSocket serverSocket;
public static final int SERVERPORT = 5000;
Thread serverThread = null;
public void startSocketServer(){
this.serverThread = new Thread(new ServerThread());
this.serverThread.start();
}
public void stopSocket(){
if(serverSocket != null){
try{
serverSocket.close();
}
catch (IOException e){
e.printStackTrace();
}
}
}
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
Log.wtf(TAG,"Socket: New Socket");
serverSocket = new ServerSocket(SERVERPORT);
if(serverSocket == null){
runOnUiThread(new Runnable() {
#Override
public void run() {
startSocketServer();
}
});
return;
}
while (!Thread.currentThread().isInterrupted() && !serverSocket.isClosed()) {
try {
socket = serverSocket.accept();
Log.wtf(TAG,"Socket: Accepting");
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
Log.wtf(TAG,"Socket: Error");
e.printStackTrace();
}
if(Thread.currentThread().isInterrupted()){
Log.wtf(TAG, "Thread Interrupted");
}
if(serverSocket.isClosed()){
Log.wtf(TAG, "serverSocket closed");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
log.info("Connected! Receiving message...");
try {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
try {
while (true) {
String line = in.readLine();
if (line != null) {
log.info(line);
}
else
break;//This will exit the loop and refresh the socket for next data
}
} catch (Exception e) {
log.error("Unexpected exception while sending / receiving messages.");
e.printStackTrace();
}
finally {
in.close();
clientSocket.close();
}
refreshSocket();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void refreshSocket(){
runOnUiThread(new Runnable() {
#Override
public void run() {
stopSocket();
startSocketServer();
}
});
}
Just call startSocketServer() to start the server socket in your code.

Java - Change Object Attribute From Other Thread

I am writing simple client-server program. The problem, that I have faced is following: I am sending an object from client to server and I start new thread for every object sent to server.
I need to get data from deserialized object and update server object attribute with this data. How can I do that?
This is my server code:
...
// Property to be updated
private FieldMap fieldMap = new FieldMap();
public void startServer() {
try {
serverSocket.bind(new InetSocketAddress("localhost", port));
(new Thread(this)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopServer() {
running = false;
Thread.currentThread().interrupt();
}
#Override
public void run() {
running = true;
while (running) {
try {
this.setChanged();
this.notifyObservers();
System.out.println("Listening for a connection");
Socket socket = serverSocket.accept();
InputHandler inputHandler = new InputHandler(socket, fieldMap);
(new Thread(inputHandler)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
...
This is listener object code:
public class InputHandler implements Runnable {
private Socket socket;
private ObjectInputStream objectInputStream;
private FieldMap map;
InputHandler(Socket socket, FieldMap map) throws IOException {
this.socket = socket;
objectInputStream = new ObjectInputStream(socket.getInputStream());
this.map = map;
}
#Override
public void run() {
try {
Lemming lemming = (Lemming) objectInputStream.readObject();
lemming.getFieldMap().union(map);
map = lemming.getFieldMap();
System.out.println(lemming);
(new Thread(lemming)).start();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
objectInputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
How to update fieldMap from InputHandler?
You need some methods like in java.uitl.Map
fieldMap.clear()
fieldMap.putAll(otherFieldMap)

Simple chat client and chat server [duplicate]

This question already has an answer here:
ObjectInputStream(socket.getInputStream()); does not work
(1 answer)
Closed 7 years ago.
I'm doing a simple echo chat and server, but methods send and receive in class Connection don't work with ObjectInputStream and ObjectOutputStream, but with PrintWriter and BufferedReader work fine.
Now I'm trying to understand the serialization using sockets, help me to understand why this code does not work:
Client
public class Client {
private Connection connection;
private String getServerAddress() {
return "localhost";
}
private int getServerPort() {
return 4444;
}
public void run() {
BufferedReader bis = new BufferedReader(new InputStreamReader(System.in));
try {
connection = new Connection(new Socket(getServerAddress(), getServerPort()));
SocketThread socketThread = new SocketThread();
socketThread.setDaemon(true);
socketThread.start();
while (true) {
String text = bis.readLine();
if (text.equalsIgnoreCase("exit"))
break;
connection.send(text);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client client = new Client();
client.run();
}
public class SocketThread extends Thread {
#Override
public void run() {
try {
while (true) {
String message = connection.receive();
System.out.println(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Connection
public class Connection implements Closeable {
private final Socket socket;
private final ObjectInputStream in;
private final ObjectOutputStream out;
public Connection(Socket socket) throws Exception {
this.socket = socket;
this.in = new ObjectInputStream(socket.getInputStream());
this.out = new ObjectOutputStream(socket.getOutputStream());
}
public void send(String message) throws Exception {
out.writeObject(message);
}
public String receive() throws Exception {
return (String) in.readObject();
}
#Override
public void close() throws IOException {
in.close();
out.close();
socket.close();
}
}
Server
public class Server {
public static void main(String[] args) {
int port = 4444;
try (ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
Socket socket = serverSocket.accept();
new Handler(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class Handler extends Thread {
private Socket socket;
public Handler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try (Connection connection = new Connection(socket)) {
while (true) {
String message = connection.receive();
if (message.equals("exit"))
break;
System.out.println(message);
connection.send("Echo: " + message);
}
} catch (Exception e) {
}
}
}
}
This is because ObjectInputStream blocks trying to read the stream header written by an ObjectOutputStream in its constructor, and you are creating both of your input streams before the output streams. You can solve this by switching the order that you create the object streams in:
this.out = new ObjectOutputStream(socket.getOutputStream());
this.in = new ObjectInputStream(socket.getInputStream());
The javadoc for the ObjectOutputStream constructor also notes that you might want to flush the stream after creating it to ensure the header is sent.

Android TCP socket: How to set a listener for incomming/received data

I'm developing a android client which communicates with a server using TCP protocol. everything is okay except for receiving data from the server. the only way i know for now, is to periodically check if there is something to read, an that's bad. is there any listener, callback or any way to get informed when the client receives a message so that i can run a method to read and process it ?
Here is my code
class QTcpSocket implements Runnable {
private String ip="";
private int port;
private Socket socket;
private DataOutputStream dataOutputStream;
private DataInputStream dataInputStream;
public QTcpSocket(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getIp() {
return this.ip;
}
public void setPort(int port) {
this.port = port;
}
public void run() {
try {
socket = new Socket(this.ip, this.port);
dataOutputStream = new DataOutputStream( socket.getOutputStream() );
dataInputStream = new DataInputStream(socket.getInputStream());
String response = dataInputStream.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String message) {
try {
byte[] buffer= message.getBytes();
dataOutputStream.write(buffer,0,buffer.length);
}catch (IOException e) {
e.printStackTrace();
}
}
public void disconnect() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean isClosed() {
return socket.isClosed();
}
}

How to stop all instances of a thread

I'm developping a socket-based game in Java about riddles in a competitive way.
The server program creates a response thread besides other threads for each player (client), what I want to do is stop (or interrupt) all those response threads once a player sends the right response.
Here's my code
public class testReponse implements Runnable {
private Socket socket;
BufferedReader in;
PrintWriter out;
String reponse="";
public testReponse(Socket socket2){
socket = socket2;
}
#Override
public void run() {
while(!reponse.equals("right")){
try {
in = new BufferedReader (new InputStreamReader (socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream());
String reponse = in.readLine();
System.out.println("Reponse : "+ reponse);
if(reponse.equals("right")){
out.println("correct");
out.flush();
} else {
out.println("incorrect");
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
It is not clear where is your server code is. However, the way I would do it is by having an AtomicBoolean as an instance variable in the server code. Once the "right" message is received from any of the clients, the value would change to false. In the code in the server side if you see that the value is false, then you stop!
This is one way to go about it but there might be better ways to do it though.
public class MyServer {
private AtomicBoolean keepServerOn = new AtomicBoolean(true);
public void setKeepServerOff() {
keepServerOn.set(false);
}
public void shouldKeepGoing() {
return keepServerOn.get();
}
public static void main(Strings[] args) {
....// where you accept clients and create TestResponse
MyServer myServer = new MyServer();
...// somewhere new TestResponse(socket, myServer);
}
}
public class testReponse implements Runnable {
private MyServer server;
private Socket socket;
private AtomicBoolean keepServerOn = new AtomicBoolean(true);
public testReponse(Socket socket2, MyServer server){
socket = socket2;
}
#Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader (new InputStreamReader (socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream());
while(server.shouldKeepGoing()){
String reponse = in.readLine();
System.out.println("Reponse : "+ reponse);
if(reponse.equals("right")){
server.setKeepServerOff();
out.println("correct");
out.flush();
} else {
out.println("incorrect");
out.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!= null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

Categories

Resources