Application of Design Pattern in C language-read nginx source code

Source: Internet
Author: User

The book and articles on the "design patterns" on the market all target object-oriented languages such as Java, C ++, and C #. It seems that the design patterns cannot be implemented without the object-oriented features, it is useless.

Is that true? The concept of design patterns is introduced from the field of architecture, and has never discriminated against process-oriented programming languages. It is only a general solution to a class of problems. Because of its class and polymorphism, object-oriented languages make it easy for developers to: hide details and encapsulate changes, which is consistent with the purpose of the design model, therefore, Masters love to integrate the design model with the object-oriented language. However, the existence is reasonable. The C language still plays a leading role in large-scale software engineering today. Its various design methods are essentially the same as the design patterns we usually see. For example, nginx, a high-performance WEB server written in pure C language, uses the design model mentioned in the market books in many places. The following uses the nginx source code to see how the C language works. Of course, all UML diagrams are drawn based on the Code intent and are not accurate (I can't draw UML in c). They are only used for easy understanding.

Strategy Mode:

This mode is used for different implementations of customer code in the "Ignorance" status. Next, let's take a look at the implementation of the C language using the nginx encapsulation of network I/O operations.

The design mode is decoupled by encapsulation changes. Therefore, we need to identify the changes of network I/O operations first. Nginx is cross-platform. It supports Linux, FreeBSD, Solaris, and other operating systems. The network Io operations of each operating system are different. This is the change point.

Therefore, nginx first defines ngx_ OS _io_t to encapsulate these changes.

typedef struct {    ngx_recv_pt        recv;    ngx_recv_chain_pt  recv_chain;    ngx_recv_pt        udp_recv;    ngx_send_pt        send;    ngx_send_chain_pt  send_chain;    ngx_uint_t         flags;} ngx_os_io_t;

Five function pointers (* _ pt) and one variable are used to send and receive network data, I understand it as abstract class in OO (every variable defined by ngx_ OS _io_t will implement these five functions again ).

Struct with function pointers. I usually think they are abstract classes in OO, and their files (a bunch of Functions) Need to correspond to OO. I like to think of them as subclasses. For a member such as void *, we need to look at it according to the intention. Generally, I will convert it into an aggregate plus inheritance relationship.

Ngx_io will choose which implementation to use in the corresponding ngx_ OS _specific_init method. The Customer Code simply needs to call the method in ngx_io.

Adapter mode:

This mode is used to adapt to the interface. Generally, we have already defined an interface, but there is a new implementation but there are different interfaces. Then the adapter starts to work. The following is the encapsulation of nginx on network I/O operations.

In Linux, there may be common Io or asynchronous Io methods. We have initially encapsulated the ngx_ OS _io_t interface, and the customer code is used directly. Now Linux implements asynchronous Io, and its calling method is completely different from that of common read/write Io interfaces. Therefore, to support AOI, an adapter is required to adapt ngx_ OS _io_t, this is the adapter method.

Ngx_ OS _aio is adapted to the native asynchronous IO Interface. In this way, the user code is still the same as before, as long as the five interface methods in ngx_io are directly used, after nginx Io supports Linux AIO, the user code does not need to be modified.

Bridge Mode:

The bridge mode is used to separate abstraction and implementation, and each of them can change independently. The following uses the core concept module of nginx as an example. Although it is somewhat far-fetched, nginx code has never been used this way: Generally, an abstract module context corresponds to only one implementation module. However, after all, this structure can achieve the purpose of abstraction and implementation separation, and the bridge mode has to correspond to this.

Nginx is a module concept throughout the process. It has a basic abstraction layer ngx_core_module_t (judging from the intent, context has the abstract interface function, although it is simply not syntactically visible ). Then, the nginx module has three basic types: event (processing various event models, such as epoll/select), HTTP (processing various HTTP protocol events ), mail (handles mail-related events ). There are many implementations for each type of module. For example, the event module has nine implementations, and each implementation here is actually a subclass.

However, when we understand the bridge mode, these subclasses will be regarded as event module instances for the moment. In the code, subclasses such as ngx_epoll_module hide some general details to ngx_event_core_module (it is more appropriate to manage the word. From this perspective, we can think that the three basic modules are separated through the context interface. Let's look at the class diagram:

In nginx, the type member in ngx_module_t is used to determine which implementation to use. In the current nginx code, if an interface is used, the corresponding type will be specified. However, this can also be used to demonstrate the bridge mode. Take the event module as an example:

Since UML is intended for OO language, the class diagrams I have drawn above are far-fetched. What is inheritance? What is aggregation? In C, function pointers or void * pointers are usually used to implement various encapsulation and polymorphism. There is no syntactic Association, so I can only judge from the code intent. The Code intent is relatively false, because different perspectives are different, so this is really hard to draw. It is too flexible. I can only look at it from a simple point of view. For example, the ngx_devpoll_module above is actually a ngx_module_t, but in fact it is most concerned with the implementation of ngx_event_actions_t, if it is based entirely on the syntax, it cannot be said at all. But from the code intent, these modules do not care about ngx_module_t, so I think they are only implementing ngx_event_module_t.

Of course, the above is just a statement of the family, do not take it seriously, if you have research on the nginx source code, you are welcome to make a brick.

Objectively speaking, the C language is indeed poorly encapsulated, just like nginx. If we want to develop a module for processing the HTTP protocol and embed it into the nginx process, we must understand what the ngx_http_module has done, the details are not hidden, and the module developers are very depressed. The above design patterns only implement code decoupling. If nginx is written in C ++, I believe that there are tens of thousands of third-party modules.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.