Thufir
Thufir

Reputation: 8487

how do I share a single socket between the producer and consumer?

How do I ensure that the Producer and Consumer each use the same socket to communicate with the server? Or, perhaps, another class should handle the socket connection? The producer and consumer are both on the client.

It seems that the socket connection is tied into the Producer and Consumer in such a way that they cannot, seemingly, be untangled, so, while I would like to put the connection into a third class, I do not see how to do so.

I very much like this pattern of Producer and Consumer, only I don't know how to implment it within the constraints of the client code so that all socket communication with the server goes through a single socket.

I suppose it might be possible to send/retrieve a unique identifier, but that would make the server overly complex.

code:

package net.bounceme.dur.client;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.bounceme.dur.data.State;
import net.bounceme.dur.data.Title;

public class Producer implements Runnable {

    private final BlockingQueue<Title> queue;
    private final String server = "localhost";
    private final int portNumber = 8080;

    public Producer(BlockingQueue<Title> q) {
        this.queue = q;
    }

    private Title connect() throws IOException, ClassNotFoundException {
        Socket socket = new Socket(server, portNumber);
        Title title = null;
        State state = State.undefined;
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
        title = (Title) objectInputStream.readObject();
        return title;
    }

    @Override
    public void run() {
        try {
            connect();
        } catch (IOException | ClassNotFoundException ex) {
            Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
            //exit?
        }
    }
}

consumer:
package net.bounceme.dur.client;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.bounceme.dur.data.State;
import net.bounceme.dur.data.Title;

public class Consumer implements Runnable {

    private final BlockingQueue<Title> queue;
    private final String server = "localhost";
    private final int portNumber = 8080;

    public Consumer(BlockingQueue<Title> q) {
        this.queue = q;
    }

    private void consume() throws IOException, ClassNotFoundException, InterruptedException {
        Socket socket = new Socket(server, portNumber);
        Title title = queue.take();
        title.setState(State.x);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        objectOutputStream.writeObject(title);
    }

    @Override
    public void run() {
        try {
            consume();
        } catch (IOException | ClassNotFoundException | InterruptedException ex) {
            Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
            //exit?
        }

    }
}

Adapted from:

http://www.journaldev.com/1034/java-blockingqueue-example-implementing-producer-consumer-problem

Upvotes: 0

Views: 1107

Answers (1)

Kayaman
Kayaman

Reputation: 73548

You need to create a single Socket and share the InputStream and OutputStream, one to each (depending on which one is reading and which one is writing to the server).

Your consume() method shouldn't initialize anything either, it should have everything ready so it can read data and process it. Your example code shows the method actually creating a new Socket and a new ObjectOutputStream, when they should be created only once.

Socket s = new Socket(server, port);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

consumer.setStream(in);     // Or vice-versa
producer.setStream(out);    // You can also provide it as a constructor argument

Upvotes: 1

Related Questions