*_at methods These methods are above a streamdo random access operations. You can specify where the read and write operations start (offset):Async_read_at (stream, offset, buffer [, completion], handler): This method executes an asynchronous read operation on a specified stream starting at offset, and when the operation ends, He would call handler. The format of handler is: void handler (const boost::system::error_code&err, size_t bytes);. Buffer can be a normal wrapper () wrapper or Streambuf method. If you specify acompletion method, it will be in each readOperationcalled after success, and then tells Boost.asio that the async_read_at operation has completed (if not, continue reading). It is in the format: size_tcompletion (const boost::system::error_code& err, size_t bytes);. When the completion method returns 0 o'clock, we assume that the read operation is complete, if a non-0 value is returned. It represents the maximum number of read bytes for the Async_read_some_at method of the next call stream. Async_write_at (stream, offset, buffer [, completion], handler): This method performs an asynchronous write operation. The meaning of the parameter is the same as the async_read_at.Read_at (stream, offset, buffer [, completion]): This method starts the read at the specified offset on an executed stream. The meaning of the parameter is the same as the async_read_at.Write_at (stream, offset, buffer [, completion]):This method begins write at the specified offset on a flow that executes. The meaning of the parameter is the same as the async_read_at.These methods do not support sockets. They are used to handle random access to the stream, that is, the stream can be accessed randomly. The socket is obviously not the case (the socket is not returned)The following example shows you how to offset from a file to256 of the locationRead 128 Bytes:Io_service Service;int main (int argc, char* argv[]) {HANDLE file =:: CreateFile ("Readme.txt", Generic_read, 0, 0,Open_always, File_attribute_normal | File_flag_overlapped,0);windows::random_access_handle H (service, file);streambuf buf;read_at (h, N, buf, transfer_exactly ());Std::istream in (&BUF);std::string Line;Std::getline (in, line);std::cout << ' first line: ' << line << Std::endl;} Asynchronous programming This section explores some of the issues you might encounter when you are doing asynchronous programming. After reading it again, I suggest that you often go back and read the book as you study it, thus enhancing your understanding of this part. Asynchronous requirements as I said before, synchronous programming is much simpler than asynchronous programming. This is because linear thinking is very simple (call a, call A to end, call B, call B to end, and then continue, which is thought in the way of event handling). In the following you will encounter this situation, such as: Five things, you do not know the order of their execution, do not know whether they will be executed! Although asynchronous programming is more difficult, you will prefer it, such as writing a server that needs to handle many concurrent accesses. The more concurrent accesses, the simpler the asynchronous programming is than the synchronous programming. Suppose: You have a software that handles 1000 concurrent accesses, each of which is sent from the client to the server and then returned to the client, ending with ' \ n '. Synchronous code, 1 Threads: using namespace boost::asio;struct client {ip::tcp::socket Sock;char buff[1024];//msg is at maximum th is Sizeint Already_read; How much has we already read?}; Std::vector<client> clients;void handle_clients () {while (true) for (int i = 0; i < clients.size (); ++i) if (CLI Ents[i].sock.available ()) On_read (Clients[i]);} void On_read (client & c) {int to_read = Std::min (1024-c.already_read, C.sock.available ()), C.sock.read_some (Buffer ( C.buff + C.already_read, to_read)) C.already_read + = To_read;if (Std::find (c.buff, C.buff + c.already_read, ' \ n ') < C. Buff +c.already_read) {int pos = Std::find (c.buff, C.buff + c.already_read, ' \ n '))-c.buff;std::string msg (C.buff, C.buff + pos); Std::copy (C.buff + pos, C.buff + 1024x768, c.buff); C.already_read-= Pos;on_re Ad_msg (c, msg);}} void On_read_msg (client & C, const std::string & msg) {//analyze message, and write backif (msg = = "Request_logi n ") c.sock.write (" request_ok\n "); else if ...} One thing you need to avoid on any server (and any web-based software) is that the code is no longer responding. In our case, we need handle_ .the clients () method blocks as little as possible. If they are blocked at any point, any incoming information needs to wait for the method to unblock and then to process them. In order to remain responsive, we only read when a socket has data, that is, if (clients[i].sock.available ()) On_read (Clients[i]). At On_read, we read only the available; Call Read_until (C.sock, buffer (...),' \ n ') would be a very bad choice, because it would be blocked until we read the complete message from a selected client (we never know when it will read the full message)The bottleneck here is the on_read_msg () method; When it executes, the incoming messages are waiting. A good on_read_msg () method implementation will guarantee that this will not happen, but it will still occur (sometimes when writing data to a socket, when his buffer is full, it will be blocked)Synchronous mode code, 10 threadsusing namespace Boost::asio;struct Client {//... same as beforebool Set_reading () {Boost::mutex::scoped_lock lk (cs_);if (is_reading_) return false;//already readingelse {is_reading_ = true; return true;}}void Unset_reading () {Boost::mutex::scoped_lock lk (cs_);is_reading_ = false;}Private:Boost::mutex Cs_;bool Is_reading_;};std::vector<client> clients;void Handle_clients () {for (int i = 0; i <; ++i)Boost::thread (handle_clients_thread);}void Handle_clients_thread () {While (true)for (int i = 0; i < clients.size (); ++i)if (clients[i].sock.available ())if (clients[i].set_reading ()) {On_read (Clients[i]);clients[i].unset_reading ();}}void On_read (client & c) {//Same as before}void on_read_msg (client & C, const std::string & msg) {//Same as before}in order to use multi-threading, we need to synchronize it, which is what set_reading () and set_unreading () do. The Set_reading () method is very important, and you want to implement "test read and then mark as read" in one step. If you have two steps ("Test read" and "Mark as read"), you might have two threads doing a test read for a client, and then you will have two threads calling On_read for a client at the same time, and the result is a data conflict that may even cause the software to crash. you will find that the code becomes extremely complex. A third option for synchronous programming is to open a thread for each connection. When concurrent threads increased, this turned out to be the least likely scenario. Then, let's look at asynchronous programming. We are constantly reading asynchronously. When a client requests something, On_read is called, then responds, and then waits for the next request (and then begins another asynchronous read operation). Async mode code, 10 thread using namespace Boost::asio;io_service service;struct client {ip::tcp::socket sock;streambuf buff;// Reads the answer from the client}std::vector<client> clients;void handle_clients () {for (int i = 0; i < clients. Size (); ++i) Async_read_until (Clients[i].sock, Clients[i].buff, ' \ n ', Boost::bind (On_read, Clients[i], _1, _2)); for (int i = 0; I & Lt 10; ++i) Boost::thread (handle_clients_thread);} void Handle_clients_thread () {Service.run ();} void On_read (client & C, const Error_code & err, size_t read_bytes) {std::istream in (&c.buff); std::string msg; Std::getline (in, msg), if (msg = = "Request_login") Boost.asio fundamentals[]c.sock.async_write ("request_ok\n", On_ Write), else if ...//now, wait for the next read from the same clientasync_read_until (C.sock, C.buff, ' \ n ', Boost::bind ( On_read, C, _1, _2));} How easy is it to find the code? ClientThere are only two members in the structure, handle_clients () only calls Async_read_until, and then it creates 10 threads, each of which calls Service.run (). These threads will handleany asynchronous read operation from the client, and thendistributes any asynchronous write operations to the client. Another thing to note: On_read () has been preparing for the next asynchronous read operation (see the last line of code)
Boost.asio C + + Network programming translator (11)