How to read from socket without blocking

后端 未结 1 920
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-25 17:43

I ran into a problem when dealing with the server, sending me initial \"greetings header\" (smtp server):

I need to read this header before send any commands and receive

相关标签:
1条回答
  • 2021-01-25 18:40

    Since no-one's provided an "official" solution yet, here's the workaround I mentioned above.

    Functions:

    # Causes stagnant 'nb' count to be updated.
    # Note asynchronous nature; this means refresh may not yet have occurred 
    # when function has exited. 
    function refreshBufsize(s)
      @async eof(s);
      return nothing;
    end;
    

    # Check if socket is blocked (refresh bytecount first)
    # Note, since refresh is asynchronous, may misreport 'blockage' until
    # 'refresh' operation is actually finished; however, if socket is actually
    # unblocked, subsequent calls of this function will eventually properly
    # report socket is not blocked, and in general, misreporting blockage once 
    # or twice when socket is actually free is probably acceptable (rather 
    # than other way round).
    function isblocked(s)
      refreshBufsize(s)
      return nb_available(s) == 0;
    end;
    

    # Peek contents of socket without consuming stream
    function peek(s, nb)
      refreshBufsize(s)
      s.buffer.seekable = true;
      Out = read(s.buffer, nb);
      seekstart(s.buffer);
      s.buffer.seekable = false
      return Out
    end;
    

    Example: (console outputs denoted as "#>" comments, for copy-pastable code)

    server = listen(9001); 
    sOut   = connect(9001); 
    sIn    = accept(server);
    
    nb_available(sIn)       
    #> 0
    isblocked(sIn)          
    #> true
    refreshBufsize(sIn); # we expect no change, as we haven't written anything yet
    isblocked(sIn)          
    #> true
    write(sOut, "Greetinks and salutations!\n")  
    #> 27
    write(sOut, "We would be honoured if you would join us.\n") 
    #> 43
    refreshBufsize(sIn);
    isblocked(sIn) # note: may say true at first (until refresh properly finished)
    #> false
    nb_available(sIn) 
    #> 27
    String( peek( sIn, 10)) # peek socket contents without consuming
    #> "Greetinks "
    String( read( sIn, nb_available( sIn))) # read (consume) as normal
    #> "Greetinks and salutations!\n"
    nb_available(sIn) # note 0 even though second buffer awaiting. needs refresh!
    #> 0
    isblocked(sIn) # note: called "refresh" under the hood 
                   # (but keep async in mind, i.e. might say 'true' at first!)
    #> false
    nb_available(sIn)
    #> 43
    String( read( sIn, nb_available( sIn)))
    #> "We would be honoured if you would join us.\n"
    isblocked(sIn)
    #> true
    

    EDIT: for comparison, a more typical "asynchronous" socket session (which typically relies on such "blocking" behaviour) would probably look something like this:

    server = listen(9002);
    sOut   = connect(9002);
    sIn    = accept(server);
    
    TaskRef = @async try 
      while true
        In = String(readavailable(sIn));
        if !isempty(In); println("Received from server: $In"); else; break; end
      end
      println("Connection closed normally");
    catch E
      println("Connection closed (with status $E)");
    end;
    
    write(sOut, "Stop repeating everything I say!\n");
    #> Received from server: Stop repeating everything I say!
    
    close(sIn)
    #> Connection closed normally
    
    0 讨论(0)
提交回复
热议问题