In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces the relevant knowledge of "Unix/Linux interface case analysis". The editor shows you the operation process through the actual case, and the operation method is simple, fast and practical. I hope this "Unix/Linux interface case analysis" article can help you solve the problem.
Blocking network programming interface
Almost all programmers come into contact with network programming from listen (), send (), recv () and other interfaces. Using these interfaces, you can easily build a server / client model.
Let's assume that we want to create a simple server program that provides a single client with a similar "ask and answer" content service.
Figure 1. Simple question-and-answer server / client model
We noticed that most of the socket interfaces are blocking. The so-called blocking interface means that the system call (usually the IO interface) does not return the call result and keeps the current thread blocked, only when the system call gets the result or when a timeout error occurs.
In fact, unless otherwise specified, almost all IO interfaces, including socket interfaces, are blocking. This brings a big problem to network programming, such as when calling send (), the thread will be blocked, during which time the thread will not be able to perform any operations or respond to any network requests. This brings challenges to the network programming of multi-client and multi-service logic. At this point, many programmers may choose a multi-threaded approach to solve this problem.
Multithreaded server program
The simplest solution to multi-client network applications is to use multithreading (or multi-processes) on the server side. The purpose of multithreading (or multi-process) is to have a separate thread (or process) for each connection so that the blocking of any one connection does not affect other connections.
There is no specific mode for the specific use of multiprocess or multithreading. Traditionally, processes are much more expensive than threads, so if you need to serve more clients at the same time, multiple processes are not recommended; if a single service executor consumes more CPU resources, such as large-scale or long-term data operations or file access, the process is more secure. Typically, you use pthread_create () to create a new thread and fork () to create a new process.
Let's assume that higher requirements are made for the above server / client model, that is, the server provides question-and-answer services to multiple clients at the same time. So we have the following model.
Figure 2. Multithreaded server model
In the above thread / time legend, the main thread waits continuously for a connection request from the client, and if there is a connection, a new thread is created and the same question and answer service as the previous example is provided in the new thread.
Many beginners may not understand why a socket can be accept multiple times. In fact, the designers of socket may have deliberately left the foreshadowing for the multi-client situation so that accept () can return a new socket. The following is the prototype of the accept interface:
Int accept (int s, struct sockaddr * addr, socklen_t * addrlen)
The input parameter s is the socket handle value inherited from socket (), bind (), and listen (). After executing bind () and listen (), the operating system has started listening for all connection requests at the specified port and, if there is a request, adding the connection request to the request queue. Calling the accept () API is to extract * connection information from the request queue of socket s and create a new socket return handle similar to s. The new socket handle is the input parameter for subsequent read () and recv (). If the request queue currently has no requests, accept () will enter the blocking state until a request enters the queue.
The above multi-threaded server model seems to solve the requirement of providing question and answer services for multiple clients, but it is not always the case. If you want to respond to hundreds of connection requests at the same time, both multi-threads and multi-processes will seriously occupy system resources and reduce the efficiency of system response to the outside world, and threads and processes themselves are more likely to enter a false death state.
Many programmers may consider using thread pooling or connection pooling. Thread pooling is designed to reduce the frequency of thread creation and destruction, maintain a reasonable number of threads, and allow idle threads to take on new execution tasks. Connection pooling maintains the cache pool of connections, reuses existing connections as much as possible, and reduces the frequency of creating and closing connections. These two technologies can reduce the system overhead, and are widely used in many large-scale systems, such as websphere, tomcat and various databases.
However, "thread pooling" and "connection pooling" technologies only alleviate the resource consumption caused by frequent calls to IO interfaces to some extent. Moreover, the so-called "pool" always has its upper limit, and when the request greatly exceeds the upper limit, the response of the "pool" system is not much better than when there is no pool. Therefore, the use of "pool" must consider the size of the response it faces, and adjust the size of the "pool" according to the response scale.
In response to the thousands or even tens of thousands of client requests that may occur at the same time in the above example, "thread pool" or "connection pool" may relieve some of the pressure, but not all the problems.
In a word, the multithreading model can solve small-scale service requests conveniently and efficiently, but in the face of large-scale service requests, the multithreading model is not a solution. In the next chapter, we will discuss trying to solve this problem with non-blocking interfaces.
Event-driven server model using select () interface
Most Unix/Linux supports the select function, which is used to detect changes in the state of multiple file handles. The prototype of the select interface is given below:
FD_ZERO (int fd, fd_set* fds) FD_SET (int fd, fd_set* fds) FD_ISSET (int fd, fd_set* fds) FD_CLR (int fd, fd_set* fds) int select (int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval * timeout)
Here, the fd_set type can be simply understood as a queue that marks a handle by the bit bit. For example, to mark a handle with a value of 16 in a fd_set, the 16th bit bit of the fd_set is marked as 1. Specific setting and verification can be realized by using macros such as FD_SET, FD_ISSET and so on. In the select () function, readfds, writefds, and exceptfds are both input and output parameters. If the readfds entered marks handle 16, select () detects whether handle 16 is readable. After select () returns, you can determine whether the "readable" event occurs by checking whether readfds is marked with handle 16. In addition, the user can set the timeout time.
The following will re-simulate the model in which data is received from multiple clients in the previous example.
Figure 4. Receive data model using select ()
The above model only describes the process of using the select () interface to receive data from multiple clients at the same time; because the select () interface can detect the read state, write state and error state of multiple handles at the same time, it is easy to build a server system that provides independent question and answer services for multiple clients.
Figure 5. Event-driven server model using select () interface
It is important to note that a connect () operation on the client side will fire a "readable event" on the server side, so select () can also detect connect () behavior from the client side.
The most critical part of the above model is how to dynamically maintain the three parameters readfds, writefds, and exceptfds of select (). As an input parameter, readfds should mark all handles to "readable events" that need to be detected, including always the "mother" handle that detects connect (); at the same time, writefds and exceptfds should mark handles to all "writable events" and "error events" that need to be detected (using the FD_SET () tag).
As output parameters, readfds, writefds, and exceptfds hold handle values for all events captured by select (). All the tag bits that the programmer needs to check (using the FD_ISSET () check) to determine which handles have the event.
The above model mainly simulates the service flow of "ask and answer". Therefore, if select () finds that a handle captures a "readable event", the server program should do recv () operation in time, prepare the data to be sent according to the received data, and add the corresponding handle value to writefds to prepare for the next select () detection of "writable event". Similarly, if select () finds that a handle catches a "writable event", the program should do the send () operation in time and be ready for the next "readable event" detection. The following figure depicts an execution cycle in the above model.
Figure 6. One execution cycle
The characteristic of this model is that each execution cycle will detect one or a group of events, and a specific event will trigger a specific response. We can classify this model as an event-driven model.
Compared with other models, the event-driven model using select () only uses a single thread (process) to execute, takes up less resources, does not consume too much CPU, and can provide services for multiple clients. If you try to build a simple event-driven server program, this model has some reference value.
But there are still many problems with this model.
First of all, the select () interface is not an event-driven option. Because when the value of the handle that needs to be probed is large, the select () interface itself takes a lot of time to poll each handle. Many operating systems provide more efficient interfaces, for example, linux provides epoll,BSD, kqueue,Solaris provides / dev/poll. If you need to implement more efficient server programs, interfaces such as epoll are more recommended. Unfortunately, the epoll interfaces of different operating systems vary greatly, so it is difficult to use interfaces similar to epoll to implement servers with good cross-platform capabilities.
Secondly, the model mixes event detection and event response together, once the execution of the event response is large, it is catastrophic to the whole model. As in the following example, the large executor 1 will directly cause the executor responding to event 2 to be delayed and reduce the timeliness of event detection to a great extent.
Figure 7. The influence of large executor on the event-driven model using select ()
Fortunately, there are many efficient event-driven libraries that can shield against these difficulties. Common event-driven libraries are the libevent library and the libev library as an alternative to libevent. These libraries choose the most appropriate event detection interface according to the characteristics of the operating system, and add technologies such as signal to support asynchronous response, which makes these libraries the best choice for building event-driven models. The following chapter describes how to use libev libraries to replace select or epoll interfaces to achieve an efficient and stable server model.
Server model using event-driven library libev
Libev is a high performance event loop / event driven library. As an alternative to libevent, its * * versions were released in November 2007. The designers of Libev claim that libev has the advantages of faster speed, smaller size and more functions, which have been proved in many tests. Because of its good performance, many systems begin to use libev libraries. This chapter describes how to use Libev to implement a server that provides question and answer services.
As a matter of fact, there are many event loop / event driven libraries, and the author has no intention of recommending that readers must use libev libraries, but only to illustrate the convenience and benefits that the event driven model brings to network server programming. Most event-driven libraries have interfaces similar to libev libraries, so as long as you understand the general principles, you can choose the right library flexibly. )
Similar to the model in the previous chapter, libev also needs to loop to detect whether an event is generated. The cycle of Libev is expressed by ev_loop structure and initiated by ev_loop ().
Void ev_loop (ev_loop* loop, int flags)
Libev supports eight event types, including IO events. An IO event is represented by ev_io and initialized with the ev_io_init () function:
Void ev_io_init (ev_io * io, callback, int fd, int events)
The initialization includes the callback function callback, the detected handle fd and the events to be detected, the EV_READ table "readable events" and the EV_WRITE table "writable events".
Now, all users need to do is add or remove some ev_io from ev_loop at the right time. Once added, the next loop will check whether the event specified by ev_io has occurred; if the event is detected, ev_loop will automatically execute ev_io 's callback function callback (); if ev_io is logged out, the corresponding event will no longer be detected.
Whether an ev_loop is started or not, you can add or remove one or more ev_io to it, and the interfaces to add and remove are ev_io_start () and ev_io_stop ().
Void ev_io_start (ev_loop * loop, ev_io* io) void ev_io_stop (EV_A_*)
As a result, we can easily get the following "ask and answer" server model. Because the server-side active termination mechanism is not taken into account, each connection can be maintained at any time, and the client is free to choose the exit time.
Figure 8. Server model using libev libraries
The above model can accept any number of connections and provide completely independent question and answer services for each connection. With the event loop / event driven interface provided by libev, the above model has the opportunity to have the characteristics of high efficiency, low resource consumption, good stability and easy to write that other models can not provide.
Because the traditional web server, ftp server and other network applications all have the communication logic of "one question and one answer", the above "question and answer" model using libev library has reference value for building similar server programs; in addition, the above model also provides a feasible implementation scheme for applications that need to implement remote monitoring or remote control.
This is the end of the introduction to "Unix/Linux Interface instance Analysis". Thank you for your reading. If you want to know more about the industry, you can follow the industry information channel. The editor will update different knowledge points for you every day.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.