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)
Related
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.
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.
Let me jump right in. Here's my Server class:
public class DTServer {
ServerSocket serverSocket;
ServerSocketHints serverSocketHints;
Socket socket;
InputStream inputStream;
OutputStream outputStream;
ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;
public DTServer(int port) {
serverSocketHints = new ServerSocketHints();
serverSocketHints.acceptTimeout = 0;
serverSocket = Gdx.net.newServerSocket(
Net.Protocol.TCP, port, serverSocketHints);
socket = serverSocket.accept(null);
}
public Serialized receiveSerialized() {
inputStream = socket.getInputStream();
try {
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
outputStream = socket.getOutputStream();
try {
objectOutputStream = new ObjectOutputStream(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
Serialized serialized = new Serialized();
try {
serialized = (Serialized) objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return serialized;
}
}
And the Client class:
public class DTClient {
Socket socket;
SocketHints socketHints;
InputStream inputStream;
OutputStream outputStream;
ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;
public DTClient(String address, int port) {
socketHints = new SocketHints();
socketHints.connectTimeout = 3000;
socketHints.keepAlive = true;
// socketHints.trafficClass = 0x04; //IPTOS_RELIABILITY
socket = Gdx.net.newClientSocket(
Net.Protocol.TCP, address, port, socketHints);
}
public void sendSerialized(Serialized serialized) {
inputStream = socket.getInputStream();
try {
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
outputStream = socket.getOutputStream();
try {
objectOutputStream = new ObjectOutputStream(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
try {
objectOutputStream.writeObject(serialized);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I create the server object like this:
public void startServer() {
new Thread(new Runnable() {
#Override
public void run() {
dtServer = new DTServer(32658);
System.out.println("Server started and listening at port: 32658.");
}
}).start();
}
And then connect to it with other instance of the program:
public void connect() {
new Thread(new Runnable() {
#Override
public void run() {
dtClient = new DTClient("127.0.0.1", 32658);
System.out.println("Connected to server at 127.0.0.1:32658");
}
}).start();
}
And everything work swell until I try to receive the object I sent:
game.dtClient.sendSerialized(new Serialized(game.gameScreen.localPlayer));
//client side
Serialized s = (Serialized)game.dtServer.receiveSerialized();
//server side
Calling receiveSerialized method causes both app instances to freeze.
Create the ObjectOutputStream before the ObjectInputStream, at both ends. Otherwise you can get a deadlock trying to read the object stream header.
You should also use the same object streams for the life of the socket, rather than a new pair per message.
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();
}
}
}
}
Ok so , i have a thread class called 'Client' every time the server accepts a connection it creates a new Client....The run method listens for messages from the client and i am useing ObjectInputStream ..
do {
ObjectInputStream in = null;
try {
in = new ObjectInputStream(socket.getInputStream());
String message = (String) in.readObject();
System.out.println(message);
}
catch (ClassNotFoundException ex) {
isConnected = false;
System.out.println("Progoramming Error");
}
catch (IOException ex) {
isConnected = false;
System.out.println("Server ShutDown");
System.exit(0);
}
} while(isConnected);
The Problem i have is that why do i have to create a new ObjectInputStream every time it loops...and if i close the input stream at the end of the loop and it loops again for another message i will get a error...Please some one help
Only create the ObjectInputStream once (outside the loop) for a client connection, then put the readObject method into the loop.
Here's a working test class:
public class TestPrg {
public static void main(String... args) throws IOException {
ServerListener server = new ServerListener();
server.start();
Socket socketToServer = new Socket("localhost", 15000);
ObjectOutputStream outStream = new ObjectOutputStream(socketToServer.getOutputStream());
for (int i=1; i<10; i++) {
try {
Thread.sleep((long) (Math.random()*3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Sending object to server ...");
outStream.writeObject("test message #"+i);
}
System.exit(0);
}
static class ServerListener extends Thread {
private ServerSocket serverSocket;
ServerListener() throws IOException {
serverSocket = ServerSocketFactory.getDefault().createServerSocket(15000);
}
#Override
public void run() {
while (true) {
try {
final Socket socketToClient = serverSocket.accept();
ClientHandler clientHandler = new ClientHandler(socketToClient);
clientHandler.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
static class ClientHandler extends Thread{
private Socket socket;
ObjectInputStream inputStream;
ClientHandler(Socket socket) throws IOException {
this.socket = socket;
inputStream = new ObjectInputStream(socket.getInputStream());
}
#Override
public void run() {
while (true) {
try {
Object o = inputStream.readObject();
System.out.println("Read object: "+o);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
In this example Strings are sent trough the ObjectStream. If you get the ClassNotFoundException (http://download.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html#readObject()) and are using an independent client and server program than you might check if both the client and the server have the class of the object to send in their class paths.
The problem i personally had with Sockets and ObjectIOStream, is that it remembers all your object addresses, so each time you send and recive them on the client, if the address of sent object is not changed it will be copied from buffer. So
So
or create new objects each time you send them ( this is not a bad idiea, because ObjectIOStream seems to has limits on this buffer)
or use another Stream for these perpouse