Introduction to Linux Web Services

Source: Internet
Author: User
Tags epoll

HTTP (Hypertext Transport Protocol), which is the Hypertext Transfer Protocol. This protocol details the rules for communicating with each other between the browser and the World Wide Web server.
Characteristics:

    1. HTTP is called Hypertext Transfer Protocol, based on request/Response mode!
    2. HTTP is a stateless protocol.

In order to facilitate the understanding of HTTP request and response protocol, use a section of PY to grasp packet analysis

import socketimport timedef handle_request(client):    time.sleep(10)    buf = client.recv(1024)    print(buf.decode(‘utf-8‘))    client.send(bytes("HTTP/1.1 200 OK\r\n\r\n",encoding=‘utf-8‘))    client.send(bytes(‘Hello World‘, encoding=‘utf-8‘))def main():    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    sock.bind((‘192.168.1.102‘, 8000))    sock.listen(2)    while True:        connection, address = sock.accept()        handle_request(connection)        connection.close()if __name__ == ‘__main__‘:    main()
The format of the request protocol GET request protocol is as follows:

Request first line;//Request Path Protocol and version, for example: get/index.html http/1.1
Request header information;//Request Header name: request header content, that is, key:value format, for example: Host:localhost
blank line;//used to separate from the request body
The request body. Get has no request body, only post has request body.

Get Capture Packet Analysis

  • get/http/1.1
    #请求主机ip:p ORT
  • host:192.168.1.102:8000
    #客户端支持的链接方式, keep a link for a while
  • Connection:keep-alive
    #表明客户端不愿意接受缓存请求, it needs to be the most immediate resource.
  • Pragma:no-cache
    #没有缓存
  • Cache-control:no-cache
    #更加支持用https
  • Upgrade-insecure-requests:1
    #与浏览器和OS相关的信息. Some websites will display the user's system version and browser version information, which is obtained by obtaining the User-agent header information;
  • user-agent:mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) applewebkit/537.36 (khtml, like Gecko) chrome/66.0.3359.139 safari/537.36
  • Accept:
    #告诉服务器, the current client can receive the document type, actually contains the /, it means that anything can be received;
  • Text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/; q=0.8
    #告诉服务器, the current client can receive the document type, actually contains the /, it means that anything can be received;
  • Accept-encoding:gzip, deflate
    #当前客户端支持的语言, you can find language-related information in the browser's tools? options;
  • accept-language:zh-cn,zh;q=0.9,en;q=0.8,cy;q=0.7
Get Request Features:
    1. No request body
    2. The data must be within 1K!
    3. Get request data is exposed in the browser's address bar
POST request
#python 发送一个post请求import requeststest = {‘key1‘: ‘value1‘, ‘key2‘: ‘value2‘}ret = requests.post("http://192.168.1.102:8000", data=test)print(ret)print(ret.text)

Packet Capture analysis

#post请求

  • post/http/1.1
  • host:192.168.1.102:8000
  • user-agent:python-requests/2.18.4
  • Accept-encoding:gzip, deflate
  • Accept: /
  • Connection:keep-alive

#请求body长度

  • Content-length:23
  • content-type:application/x-www-form-urlencoded

#请求体

    • Key1=value1&key2=value2
Post Request features
    1. Data does not appear in the address bar
    2. There is no limit to the size of data
    3. There is a request body
    4. If Chinese is present in the request body, URL encoding will be used!
Response
  • http/1.1 OK
    Hello World

The format of the response protocol is as follows:

Response to the first line;
Response header information;
Empty line;
The response body.

Response Protocol Description

http/1.1 OK: The response protocol is HTTP1.1, the status code is 200, indicating the success of the request, OK is the interpretation of the status code;
server:wsgiserver/0.2 cpython/3.5.2: Version information of the server;
Content-type:text/html;charset=utf-8: The encoding used by the response body is UTF-8;
content-length:724: The response body is 724 bytes;
SET-COOKIE:JSESSIONID=C97E2B4C55553EAB46079A4F263435A4; Path=/hello: A cookie that responds to the client;
date:wed, Sep 04:15:03 GMT: Response time, which may have a 8-hour time zone difference;

TCP three-time handshake four-break description

Service-side code

import socketserver = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)back_log = 5buffer_size = 1024ip_port = (‘192.168.1.102‘, 8000)server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)server.bind(ip_port)server.listen(back_log)print(‘waiting.....‘)doing = 1while doing > 0:    conn, addr = server.accept()    while doing > 0:        data = conn.recv(buffer_size).decode(‘utf-8‘)        if not data :            break        print(‘recv:‘,data)        print(‘test:‘)        if data == ‘exit‘:            conn.close()            break        if data == ‘exitall‘:            doing=0            break        else:            if data:                conn.send(data.upper().encode(‘utf-8‘))server.close()

Client code

import socketclient = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)buffer_size = 1024ip_port = (‘192.168.1.102‘, 8000)client.connect(ip_port)while True:    msg = input(‘input>>>\n‘).strip()    if not msg:        continue    client.send(bytes(msg,encoding=‘utf-8‘))           data = client.recv(buffer_size).decode(encoding=‘utf-8‘)    print(data)    if msg == ‘exit‘:        breakclient.close()

1, open a monitor on the 8000 port TPC process

[[email protected] conf.d]# ss -antp|grep 8000LISTEN     0(当前等待的已经是ESTAB的连接数量,排除正在通信的)      5(表示接收连接最大数)      192.168.1.102:8000                     *:*                   users:(("python3.6",pid=29528,fd=3))

We use watch to see how the servers are connected.
2, connect a client, process observation
In fact, this stage has a lot of state changes, the server will be from SYN_RECV to Estab

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:36:44 2018LISTEN     0      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=39882,fd=3))ESTAB      0      0  192.168.1.102:8000               192.168.1.101:58132               users:(("python3.6",pid=39882,fd=4))

2.1 Disconnect, Process watch
Client disconnects, time-wait is waiting for server to disconnect

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:41:39 2018LISTEN     0      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=41041,fd=3))TIME-WAIT  0      0  192.168.1.102:8000               192.168.1.101:59438

After a few seconds the client confirms that it has been disconnected, because it is possible that the server-side data sent to the client has not been sent out, so the server confirms

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:43:50 2018LISTEN     0      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=41041,fd=3))

There is also a case where close-wait occurs because the client disconnects, and the server is connected to the client, possibly a bug in the server (this phase is quickly confirmed by the server)

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:47:46 2018LISTEN     0      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=41041,fd=3))CLOSE-WAIT 0      0  192.168.1.102:8000               192.168.1.101:61056               users:(("python3.6",pid=41041,fd=4))

Another set of tests to test multiple connections
3. Connect 3 clients first, process observation
Altogether 3 estab connections 1 to non-blocking, 2 blocked

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:51:28 2018LISTEN     2      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=43041,fd=3))ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62088ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62079ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62070               users:(("python3.6",pid=43041,fd=4))

3.1 In connection 3 clients, altogether 6, process observation
6 established estab connections, 1 non-blocking, 5 blocked

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:52:02 2018LISTEN     5      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=43041,fd=3))ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62249ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62088ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62233ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62242ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62079ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62070               users:(("python3.6",pid=43041,fd=4))

3.2 Continue to add 3 clients, total 9 connections, process observation
Altogether 9 connections, 1 non-blocking estab,6 blocking estab,2 waiting for a server response syn-recv

 every 1.0s:ss-antp|grep 8000 Sat May 10:52:24 2018LISTEN 6 5 192.168.1.102:8000 *:* Users: (("PYT hon3.6 ", pid=43041,fd=3)) SYN-RECV 0 0 192.168.1.102%if355331399:8000 192.168.1.101:62369syn-recv 0 0 192.168.1.102:8000 192.168.1.101:62364estab 0 0 192.168.1.102:8000 192.168. 1.101:62249estab 0 0 192.168.1.102:8000 192.168.1.101:62088estab 0 0 192.168.1.102:800 0 192.168.1.101:62233estab 0 0 192.168.1.102:8000 192.168.1.101:62355estab 0 0 192.168.1.102:8000 192.168.1.101:62242estab 0 0 192.168.1.102:8000 192.168.1 .101:62079estab 0 0 192.168.1.102:8000 192.168.1.101:62070 Users: (("python3.6", pid= 43041,fd=4)) 

After a few seconds, the server has not responded to client requests and the server is disconnected

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:53:33 2018LISTEN     6      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=43041,fd=3))ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62249ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62088ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62233ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62355ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62242ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62079ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62070               users:(("python3.6",pid=43041,fd=4))

3.3 Client Disconnects the first connection, which is the non-blocking one, to observe
1 wait for the server to confirm the disconnection, 1 non-blocking, 5 blocking. Previous 62070 non-blocking disconnects, second blocking state to non-blocking

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:54:25 2018LISTEN     5      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=43041,fd=3))ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62249ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62088ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62233ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62355ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62242ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62079               users:(("python3.6",pid=43041,fd=4))TIME-WAIT  0      0  192.168.1.102:8000               192.168.1.101:62070

3.4 Continue to disconnect 2 connections, observe
2 Waiting acknowledgement disconnects, 1 non-blocking, 3 blocked

Every 1.0s: ss -antp|grep 8000                                                                                          Sat May 12 10:56:25 2018LISTEN     3      5  192.168.1.102:8000                     *:*                   users:(("python3.6",pid=43041,fd=3))ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62249TIME-WAIT  0      0  192.168.1.102:8000               192.168.1.101:62088ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62233               users:(("python3.6",pid=43041,fd=4))ESTAB      4      0  192.168.1.102:8000               192.168.1.101:62355ESTAB      0      0  192.168.1.102:8000               192.168.1.101:62242TIME-WAIT  0      0  192.168.1.102:8000               192.168.1.101:62079
    • This analyzes the three-time handshake four disconnects:
      1, in three handshake, the client initiates the request, the SYN SEQ request signal
      2, the server received the signal to SYN-RECV
      3, the server to view the semi-connection pool, if the number can be received, to the client to confirm, and send the server request signal, state or SYN-RECV
      4, the client receives the consent of the server, establishes a client-to-server connection (DDoS attack, this phase does not give confirmation), the client agrees to the server connection, and then confirms the information
      5, the server receives the client confirmation, establishes the server to the client connection, the State from Syn-recv to the Estab
      6, three times handshake success, the two sides can be friendly exchanges, each communication is to send a request to confirm receipt.
      7, the client sends a disconnect request, the status to Close_wait
      8, the server confirms the consent, the client to the server request disconnects
      9, the server confirms that the request can be closed, send the request
      10, client confirmation, disconnect server to client connection
Introduction to Common IO models

Introducing the IO model provides some basic understanding because of the high concurrency of configuring Web services.
There are some concepts of process threads, presumably the process before the data are independent, the switching process is much more expensive than the switching thread, the thread is able to share the process resources, here do not explain in detail

1, blocking IO The above service-side Socekt is blocking IO

2. Non-blocking IO

Import Socketimport timeserver = Socket.socket (Family=socket.af_inet, Type=socket. SOCK_STREAM) buffer_size = 1024ip_port = (' 127.0.0.1 ', 8000) server.setsockopt (socket. Sol_socket,socket. so_reuseaddr,1) Server.bind (Ip_port) Server.listen (5) server.setblocking (False) #非阻塞print (' Waiting ... ') doing =                1while doing > 0:try:conn, addr = server.accept () while doing > 0:try: data = Conn.recv (buffer_size). Decode (' utf-8 ') if not data:break print                 (' recv: ', data) print (' Test: ') if data = = ' exit ': Conn.close () if data = = ' Exitall ': doing = 0 break else:i F Data:conn.send (Data.upper (). Encode (' Utf-8 ')) except Exception as E:ti Me.sleep (1) print (e) except Exception as E:time.sleep (1) prinT (e) Server.close () 
3. IO Multiplexing-select

The user process calls select and the kernel is responsible for the state of the sokect that all select adds, and when the data in any one socket is ready, select returns and returns all the sockets added to the select. This time the user process then invokes the read operation, copying the data from the kernel to the user process. IO multiplexing Select divides the CPU in the time-to-find space, and it has been implemented to single-threaded high concurrency. The disadvantage is also obvious, the level of consumption is higher, non-active socket because no operation, select also rely on file descriptors, each server can open the file descriptor resource is also limited.

Service-side code

import socketimport selectsk=socket.socket()sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)sk.bind(("127.0.0.1",8008))sk.listen(5)inputs=[sk,]while True:    r, w, e = select.select(inputs, [], [], 5)    for i in r:        if i is sk:  # 看上述r描述            conn, add = i.accept()  # 把r进来的socket接收到  不接收会一直存在内核            inputs.append(conn)        else:            data_byte = i.recv(1024)            print(str(data_byte, ‘utf-8‘))            inp = input(‘回答%s号客户>>>‘ % inputs.index(i))            i.sendall(bytes(inp, ‘utf-8‘))    print(‘>>>>>>‘)

Client code

import socketsk=socket.socket()sk.connect(("127.0.0.1",8000))while 1:    inp=input(">>").strip()    sk.send(inp.encode("utf8"))    data=sk.recv(1024)    print(data.decode("utf8"))
IO multiplexing-poll-epoll

Poll essence is not the same as SELECT, only the limit of the file descriptor is canceled.
Epoll after Linux kernel 2.6, and support horizontal triggering and edge triggering, edge trigger means to return the file descriptor changes in the socket, greatly reduce the cost of the server, the kernel copy data to the user space using mmap memory mapping technology, eliminating the file descriptor in the system call replication overhead, another The essence of the improvement is that Epoll uses event-based readiness notification, and once a file descriptor is in place, the kernel uses a callback mechanism like callback to quickly activate the file descriptor.
How event notifications are implemented

from concurrent.futures import ProcessPoolExecutorimport requestsdef task(url):    response = requests.get(url)    return responsedef done(future,*args,**kwargs):    response = future.result()    print(response.status_code,response.content)pool = ProcessPoolExecutor(7)url_list = [    ‘https://www.taobao.com‘,    ‘https://www.sina.com‘,    ‘https://www.baidu.com‘,]for url in url_list:    print(url)    v = pool.submit(task,url)    v.add_done_callback(done)print(‘all‘)pool.shutdown(wait=True)

The implementation of Epoll is particularly simple in Python, and the selectors module Epollselector
Service side

import selectorsimport socketsel = selectors.EpollSelector()def accept(sock, mask):    conn, addr = sock.accept()  # Should be ready    print(‘accepted‘, conn, ‘from‘, addr)    conn.setblocking(False)    sel.register(conn, selectors.EVENT_READ, read)def read(conn, mask):    data = conn.recv(1000)  # Should be ready    if data:        print(‘echoing‘, repr(data), ‘to‘, conn)        conn.send(data)  # Hope it won‘t block    else:        print(‘closing‘, conn)        sel.unregister(conn)        conn.close()sock = socket.socket()sock.bind((‘localhost‘, 1234))sock.listen(100)sock.setblocking(False)sel.register(sock, selectors.EVENT_READ, accept)while True:    events = sel.select()    for key, mask in events:        callback = key.data        callback(key.fileobj, mask)

Client

import socketclient = socket.socket()client.connect((‘localhost‘, 9000))while True:    cmd = input(‘>>> ‘).strip()    if len(cmd) == 0 : continue    client.send(cmd.encode(‘utf-8‘))    data = client.recv(1024)    print(data.decode())client.close()

Introduction to Linux Web Services

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.