简体   繁体   English

阻止非阻塞套接字客户端连接

[英]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) :). 首先,我不是开发人员(并且我只编写了2个星期的代码),所以请随意告诉我我完全误解了这件事(而且,我为自己编写了所有这些内容,所以我确定这是超级不酷):)。 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!): 我的解决方案如下(我正在用Java编写它,因为我已经读过它是一种快速而又好的编程语言,但是我很乐意在需要时进行更改……希望是不需要的!):

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? 如果我从套接字读取并且消息是“重新连接到API”,如何确保在进行其他任何读/写操作之前发生这种情况?
  • 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! 我已经看到可以使用Netty或其他东西简化所有操作,但是我已经被很多东西blo肿了! :( :(

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. 我一直在这里阅读,不要使用阻塞连接:D。 But now it makes perfect sense the different scenarios. 但是现在,在不同情况下完全可以理解了。 – Will –威尔

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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