UVW code (1) and uvw code
The blog garden is a place where you can learn a lot. I believe many people, like me, who have been in the garden for three years, do not know how much code they copied or how many blogs they read, I have never written a blog. Really sin.
This time I am going to write several articles about reading and understanding the source code of this project. Everyone will learn from each other. I may not just write the source code, but I will do a lot of extensions, for example, new c ++ syntaxes and other tools. We are not a good guy. If there is any ambiguity in the text, please leave a message in the comment area. Let's discuss it and make improvements to avoid mistakes.
Not to mention nonsense. Start now.
I recently looked at the source code of a project uvw. Many people may not know about it. People who have worked on network programming should know about libuv. uvw is a project I found on github that encapsulates libuv with c ++, and the source code author is continuously updating.
A Brief Introduction:
Libuv: is a cross-platform network library, specific can refer to the blog: http://www.cnblogs.com/haippy/archive/2013/03/17/2963995.html and blog libuv series of articles.
Uvw: c ++ 14 package libuv. The author should be a foreigner. The code quality should not be mentioned, especially the comments. It is very detailed and worth waiting for cainiao to learn.
Github address: https://github.com/skypjack/uvw
First, you must develop the code,
1, direct download, address: https://codeload.github.com/skypjack/uvw/zip/master
2. git clone https://github.com/skypjack/uvw.git
Note: The Current Directory of./src/uvw. hpp is the code root directory.
Basically, the code is switched to src in the src file. Right, you are not mistaken. It is all hpp files. So if you want to use this library, just copy src to your project. It is very convenient to use, but do not forget to include the libuv header file and link the libuv library in your project. In addition, uvw has restrictions on the libuv version. You can view the version of libuv in the github tag. If you use method 2, you can run the "git tag-l" command to view the version. (About git this thing, if you do not know about the official, you can refer to the cainiao Tutorial: http://www.runoob.com/git/git-tutorial.html or go to the git official website, there are very detailed information)
I. Let's see how to use it first.
Copy a piece of code (./test/main. cpp ):
1 # include ".. /src/uvw. hpp "2 # include <cassert> 3 # include <iostream> 4 # include <memory> 5 # include <chrono> 6 7 8 void listen (uvw: Loop & loop) {9 std: shared_ptr <uvw: TcpHandle> tcp = loop. resource <uvw: TcpHandle> (); // create a TcpHandle 10 11 tcp-> on <uvw: ErrorEvent> ([] (const uvw: ErrorEvent &, uvw:: TcpHandle &) {// function for error registration, 12 std: cout <"error" <std: endl; 13 }); 14 15 tcp-> once <uvw: Listen Event> ([] (const uvw: ListenEvent &, uvw: TcpHandle & srv) {// register the listening Event function 16 std :: cout <"listen" <std: endl; 17 18 std: shared_ptr <uvw: TcpHandle> client = srv. loop (). resource <uvw: TcpHandle> (); // create a TcpHandle for the new client to connect 19 20 clients-> on <uvw: ErrorEvent> ([] (const uvw:: ErrorEvent &, uvw: TcpHandle &) {// function 21 std: cout when registering an error for the client <std: endl; 22 }); 23 24 client-> on <uvw: CloseEve Nt> ([ptr = srv. shared_from_this ()] (const uvw: CloseEvent &, uvw: TcpHandle &) {// register the client to close the function 25 std: cout <"close" <std :: endl; 26 ptr-> close (); // when the client is disabled, server 27 is also disabled); 28 29 srv. accept (* client); // server accept 30 31 uvw: Addr local = srv. sock (); 32 std: cout <"local:" <local. ip <"" <local. port <std: endl; 33 34 uvw: Addr remote = client-> peer (); 35 std: cout <"remote: "<Remote. ip <"" <remote. port <std: endl; 36 37 client-> on <uvw: DataEvent> ([] (const uvw: DataEvent & event, uvw: TcpHandle &) {// register the client to receive the data event function 38 std: cout. write (event. data. get (), event. length) <std: endl; // read data is saved in the event. You can directly use 39 std: cout <"data length:" <event. length <std: endl; 40}); 41 42 client-> on <uvw: EndEvent> ([] (const uvw: EndEvent &, uvw :: tcpHandle & handle ){ // Register the client data read end function. When the socket does not have data to read, this event 43 std: cout <"end" <std: endl; 44 int count = 0; 45 handle. loop (). walk ([& count] (uvw: BaseHandle &) {++ count ;}); // gets active sockets in the main loop. Here there are two 46 std servers and clients:: cout <"still alive:" <count <"handles" <std: endl; 47 handle. close (); // close client connection 48}); 49 50 client-> read (); // start to read data, which is the same as uv_read_start, the above registration event operations are called in no particular order. 51}); 52 53 tcp-> once <uvw: CloseEvent> ([] (const uvw: CloseEvent &, uvw: TcpHandle &) {54 std :: cout <"close" <std: endl; 55}); 56 57 tcp-> bind ("127.0.0.1", 4242); // bind, IPv4 and IPv6 are supported here. bind is a template function 58 tcp-> listen (); // listen 59} 60 61 62 void conn (uvw: Loop & loop) {63 auto tcp = loop. resource <uvw: TcpHandle> (); // The following is similar to that in listen. Do not comment 64 65 tcp-> on <uvw :: errorEvent> ([] (const uvw: ErrorEvent &, uvw: TcpHandle &) {66 std: cout <"error" <std: endl; 67}); 68 69 tcp-> once <uvw: WriteEvent> ([] (const uvw: WriteEvent &, uvw: TcpHandle & handle) {70 std :: cout <"write" <std: endl; 71 handle. close (); 72}); 73 74 tcp-> once <uvw: ConnectEvent> ([] (const uvw: ConnectEvent &, uvw: TcpHandle & handle) {75 std: cout <"connect" <std: endl; 76 77 auto dataTryWrite = std :: unique_ptr <char []> (new char [1] {'A'}); // The following operation is performed to send data 78 int bw = handle to the server. tryWrite (std: move (dataTryWrite), 1); 79 std: cout <"written:" <(int) bw) <std: endl; 80 81 auto dataWrite = std: unique_ptr <char []> (new char [2] {'B', 'C'}); 82 handle. write (std: move (dataWrite), 2); 83}); 84 85 tcp-> once <uvw: CloseEvent> ([] (const uvw: CloseEvent &, uvw: TcpHandle &) {86 std: cout <"close" <std: endl; 87}); 88 89 tcp-> connect ("127.0.0.1 ", 4242); 90} 91 92 void g () {93 auto loop = uvw: Loop: getDefault (); // obtain the default event loop 94 listen (* loop ); 95 conn (* loop); 96 loop-> run (); // start the event loop 97 loop = nullptr; 98} 99 100 int main () {101g (); 102}
(Why is there no font I like)
It seems quite long. The structure here seems clear.
Ii. Take a closer look
1. server operations
The listen () function basically contains all server operations. The basic process is:
Create TcpHandle (9th rows) --> bind (57th rows) --> listen (58th rows)
In ListenEvent, You can see row 18th and create a TcpHandle client to receive client connections:
Create TcpHandle (18th rows) --> accept (29th rows) --> read (50th rows)
The other code is the process of event processing. All event processing is written using Lambda expressions, such:
1 tcp-> on <uvw: ErrorEvent> ([] (const uvw: ErrorEvent &, uvw: TcpHandle &) {// function for error registration, 2 std :: cout <"error" <std: endl; 3 });
Lambda has two parameters:
{Event}: events. Many Event types can be viewed in the Code, such as CloseEvent and ConnectEvent. (You should know the Event by name)
{Handle}: Source type. Here there may also be types in libuv such as UdpHandle. Let's talk about the source code later.
After debugging, the {Handle} In the event processing anonymous function is actually the same as the created TcpHandle.
2. client operations
In the conn function, create a TcpHandle and call connect to the server. The other is related events.
In addition, the client sends data:
1 std: cout <"connect" <std: endl; 2 3 auto dataTryWrite = std :: unique_ptr <char []> (new char [1] {'A'}); // The following operation sends data to the server: 4 int bw = handle. tryWrite (std: move (dataTryWrite), 1); 5 std: cout <"written:" <(int) bw) <std: endl; 6 7 auto dataWrite = std: unique_ptr <char []> (new char [2] {'B', 'C'}); 8 handle. write (std: move (dataWrite), 2 );
We can see that two data writing functions are called, tryWrite and write, which are equivalent to uv_write and uv_try_write. I will give the author's comment on tryWrite:
/**
* @brief Queues a write request if it can be completed immediately.
*
* Same as `write()`, but won’t queue a write request if it can’t be
* completed immediately.<br/>
* An ErrorEvent event will be emitted in case of errors.
*
* @param data The data to be written to the stream.
* @param len The lenght of the submitted data.
* @return Number of bytes written.
*/
It means that tryWrite will also send data, but it will not be completed immediately, and it will not guarantee that all data will be sent at one time. Write will add the unsent data to the loop again and wait for the next sending.
3. Summary
It can be seen that the author uses a large number of Lambda to replace various callbacks in libuv. In contrast, Lambda increases readability a lot.
In addition, the Code uses a large number of template functions to differentiate event types. The author's source code should use a lot of generics,
Iii. Related Knowledge
1. Lambda
Lambda is also called an anonymous function, this is a blog post, you can learn a little or review: http://www.cnblogs.com/langzou/p/5962033.html
PS: The English name of this anonymous function. There are a bunch of spelling: Lamda, Lamba, Lamdba, and Ladbda... It's really amazing.
I would like to emphasize that although writing a name does not have much impact on our learning, in a rigorous manner, his English name should be correctly spelled
Lambda pronunciation: lan B (m) da (Lamda) ['l hybrid md]
It is the transliteration of 'λ ', which is also the spelling on Baidu encyclopedia. It can also be seen on page 5th of "C ++ Primer 346", so remember it in the future, avoid getting jokes. Haha.
In row 24th:
1 client-> on <uvw: CloseEvent> ([ptr = srv. shared_from_this ()] (const uvw: CloseEvent &, uvw: TcpHandle &) {// register the client to close function 2 std: cout <"close" <std :: endl; 3 ptr-> close (); // when the client is closed, server4 is also closed });
Have you noticed what ptr = srv. shared_from_this () is?
Shouldn't [] be used to capture external variables in Lambda? Why does it seem to define a ptr variable and initialize it with shared_from_this. However, it is obvious that this ptr does not have a parameter type and does not declare ptr in the context. Isn't that strange.
After reading a lot of books, in the http://zh.cppreference.com/w/cpp/language/lambda found the following section:
1. Capture with the initialization device. The action is like declaring it and displaying the variables that are captured with the Type auto declaration, the declared area of the variable is the lambda expression body (that is, it is not in the scope of its initialization), except: 2 if captured to copy, the non-static data member of the closure is another way to refer to the automatic variable. 3. If the object is captured as a reference, the lifetime of the referenced variable ends at the end of the lifetime of the closure object. 4. This is used to capture only the movement type. For example, x = std: move (x) Capture 5 int x = 4; 6 auto y = [& r = x, x = x + 1] ()-> int 7 {8 r + = 2; 9 return x * x; 10} (); // update :: x is 6 and y is initialized to 25.
It can be seen that the capture with the initialization tool is used, which is a new feature added in c ++ 14.
In the first line, we can know that the capture with the initialization tool automatically declares the variables as auto type and can initialize the declared variables. Remember, it is initialization. If the preceding example is written as follows:
1 int x = 4; 2 auto y = [& r = x, r = x + 1] ()-> int // error 3 {4 r + = 2; 5 return x * x; 6 }();
Yes. In addition, if you do not initialize the SDK, a compilation error occurs.
Now let's look at the 24th-line source code. It should be okay?
After learning about this, I found another article about this capture type: http://blog.csdn.net/big_yellow_duck/article/details/52473055.
Let's take a look at it together. It seems that I have to buy a free version of objective Modern C ++.
2. smart pointer
This I will not introduce, or blog Park articles, you can learn or review: http://www.cnblogs.com/qq329914874/p/6653412.html
Iv. Next
Thank you for seeing this. I am not very good at writing this article. I am wronged.
Next I will talk about a basic class in UVW, Emitter
It may take a few days.