приведите в порядок код для асинхронного IO

Здесь работает реализация CookieJar для OkHttp3. Если у вас есть несколько экземпляров OkHttp3 (обычно вы должны иметь только один экземпляр и использовать его как синглетон), вы должны установить один и тот же экземпляр cookiejar для всех клиентов http, чтобы они могли делиться файлами cookie !!! В этой реализации не сохраняются файлы cookie (все они будут удалены при перезапуске приложения), но должно быть легко реализовать постоянство SharedPreferences вместо списка файлов cookie в cookie (cookieStore).

    CookieJar cookieJar = new CookieJar() {
        private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

        @Override
        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
            cookieStore.put(url.host(), cookies);
        }

        @Override
        public List<Cookie> loadForRequest(HttpUrl url) {
            List<Cookie> cookies = cookieStore.get(url.host());
            return cookies != null ? cookies : new ArrayList<Cookie>();
        }
    };
    OkHttpClient httpClient = new OkHttpClient.Builder()
            .cookieJar(cookieJar)
            .build();
23
задан Mankarse 28 May 2014 в 17:08
поделиться

3 ответа

Предлагаю взглянуть на: http://www.kegel.com/c10k.html , во-вторых, взгляните на существующие библиотеки, такие как libevent, Boost.Asio которые уже выполняют свою работу и смотрят, как они работают.

Дело в том, что подход может быть разным для каждого типа системного вызова:

  • select is simple Reaction
  • epoll имеет интерфейс, запускаемый по фронту или по уровню, который требует другой подход
  • iocp - проактор, требует другого подхода

Предложение: используйте хорошую существующую библиотеку, такую ​​как Boost.Asio для C ++ или libevent для C.

РЕДАКТИРОВАТЬ: Вот как ASIO справляется с этим

class connection {
   boost::asio:ip::tcp::socket socket_;
public:
   void run()
   {
         // for variable length chunks
         async_read_until(socket_,resizable_buffer,'\n',
               boost::bind(&run::on_line_recieved,this,errorplacehplder);
         // or constant length chunks
         async_read(socket_,buffer(some_buf,buf_size),
               boost::bind(&run::on_line_recieved,this,errorplacehplder);
   }
   void on_line_recieved(error e)
   {
        // handle it
        run();
   }

};

Потому что ASIO работает как проактор он уведомляет вас, когда операция завершена и обрабатывает EWOULDBLOCK внутренне.

Если вы используете слово «реактор», вы можете смоделировать это поведение:

 class conn {
    // Application logic

    void run() {
       read_chunk(&conn::on_chunk_read,size);
    }
    void on_chunk_read() {
         /* do something;*/
    }

    // Proactor wrappers

    void read_chunk(void (conn::*callback),int size, int start_point=0) {
       read(socket,buffer+start,size)
       if( complete )
          (this->*callback()
       else {
          this -> tmp_size-=size-read;
          this -> tmp_start=start+read;
          this -> tmp_callback=callback
          your_event_library_register_op_on_readable(callback,socket,this);
       }
    }
    void callback()
    {
       read_chunk(tmp_callback,tmp_size,tmp_start);
    }
 }

Что-то вроде этого.

16
ответ дан 29 November 2019 в 02:46
поделиться

You want to decouple "io" from processing, at which point the code you read will become very readable. Basically you have:


    int read_io_event(...) { /* triggers when we get a read event from epoll/poll/whatever */

     /* read data from "fd" into a vstr/buffer/whatever */

     if (/* read failed */) /* return failure code to event callback */ ;

     if (/* "message" received */) return process_io_event();

     if (/* we've read "too much" */) /* return failure code to event callback */ ;

     return /* keep going code for event callback */ ;
    }


    int process_io_event(...) {
       /* this is where you process the HTTP request/whatever */
    }

...then the real code is in process event, and even if you have multiple requests responses it's pretty readable, you just do "return read_io_event()" after setting a state or whatever.

0
ответ дан 29 November 2019 в 02:46
поделиться

Конечные автоматы - хороший подход. Это немного сложностей, которые избавят вас от головной боли в будущем, когда будущее начинается очень-очень скоро. ; -)

Другой метод - использовать потоки и выполнять блокирующий ввод-вывод для одного fd в каждом потоке. Компромисс здесь заключается в том, что вы делаете ввод / вывод простым, но может усложнять синхронизацию.

6
ответ дан 29 November 2019 в 02:46
поделиться