简体   繁体   中英

Blocking a non-blocking socket client connection

First, I'm not a developer (and I've been coding only for 2 weeks), so feel free to tell me I'm completely misunderstanding the thing (also, I wrote all of this for myself, so I'm sure it's super not cool) :). I want to learn and get it right, so I'm keen to listen to suggestions or complete rewrites.

I want to connect to a socket in non-blocking mode (I'm the client, not the server). I'll mainly need to read from it, but sometimes I'll need to write to it, too. The procedure is as follows:

  • Connect to socket
  • Send some initial requests to login to the server
  • Read from the socket
  • Sometimes, write some stuff (subscribe to certain information, for example)

My solution is as follows (I'm writing it in Java, because I've read it's a fast and good programming language, but I'm happy to change if required... hopefully not needed though!):

public class SocketClient {

    public static void main(String[] args) {
        new Feed().init();
    }

    private boolean isSocketConnected() {
        return socket != null && socket.isConnected();
    }

    public void init() {
        try {
            if (isSocketConnected()) {
                // What here if I'm in non-blocking mode?
                // Would be good to know if the "close API" request succeeded
                // otherwise next time I won't be able to connect to their socket...

                sendCloseRequestToApi();
                socket.close();
            }

            run();
        } catch (Exception e) {
            if (isSocketConnected()) {
                // Same question as above...
                sendCloseRequestsToApi();
                socket.close();
            }
        }
    }

    public void run() throws IOException {
        System.out.println("Starting connection in blocking mode...");

        SocketChannel channel = SocketChannel.open();
        socket = channel.socket();
        socket.setReceiveBufferSize(RECEIVE_BUFFER_SIZE);
        socket.setSendBufferSize(SEND_BUFFER_SIZE);
        channel.connect(new InetSocketAddress("127.0.0.1", 2121));
        channel.finishConnect();

        System.out.println("Finished connecting in blocking mode");

        // Writes to the socket (user and password)
        initialiseTheApi();

        System.out.println("Sent API requests in blocking mode");
        System.out.println("Now we should probably go non-blocking (I guess)");

        channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
        selector = Selector.open();
        channel.configureBlocking(false);

        System.out.println("Selector created and switched to non-blocking mode...");

        long timeWithoutData = 0;
        boolean needsReconnection = false;
        while (!needsReconnection) {
            selector.select();
            Iterator < SelectionKey > keys = selector.selectedKeys().iterator();

            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                keys.remove();

                if (!key.isValid()) {
                    continue;
                }

                if (key.isWritable()) {
                    // Execute write...
                    // What if I need to know the result to the write operation?
                }

                if (key.isReadable()) {
                    int dataRead = readDataFromSocket(buffer);

                    buffer.flip();
                    if (buffer.remaining() > 0) {
                        // I process the data read here,
                        // but sometimes the data sent is
                        // "reconnect to API". So I need to close
                        // the connection and start again.

                        // How can I do that if I'm in non-blocking mode?
                        // I mean, I need to make sure when I send that request
                        // (for reconnection).
                        // I need to know that the request got to the server and
                        // was processed OK before moving on and
                        // reading/writing again...
                    }

                    if (dataRead > -1) {
                        timeWithoutData = 0;
                    } else {
                        if (timeWithoutData > 0) {
                            long diffInMillis = System.currentTimeMillis() - timeWithoutData;
                            if (diffInMillis > 2000) {
                                System.out.println("Timeout or something? I need to reconnect I think");
                                needsReconnection = true;
                            }
                        } else {
                            timeWithoutData = System.currentTimeMillis();
                        }
                    }

                    // Do I even need this? Already did it before, right?
                    key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                }
            }
        }

        if (needsReconnection) {
            // We need full reconnection, go back up and reconnect
            init();
        }
    }
}

I removed imports and other non-useful methods for convenience, and to keep the post short.

As you can see in my questions in the code (plus some added ones):

  • Reconnection: If I'm in non-blocking mode, how do I know that my request got sent successfully to the server
  • If I read from the socket and the message is "Reconnect to API", how can I make sure that happens before any other read / write?
  • Do I need to send the interestedOps over and over again?
  • I should only connect once to the socket. The fact that I'm non-blocking doesn't change that, right?

I've seen this could all be simplified using Netty or something, but I'm already bloated with so much stuff! :(

I hope my questions are clear. Let me know otherwise, please.

Thanks a lot.

I was trying to do something that just didn't make sense. In my case I can definitely use a blocking connection, which I just didn't know about :/. Internet is a bad source of information sometimes! I kept reading over here not to use a blocking connection :D. But now it makes perfect sense the different scenarios. – Will

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM