Python Select 解析

news/2024/7/9 16:16:53 标签: epoll, 操作系统, python

首先列一下,sellect、poll、epoll三者的区别 
select 
select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。

select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。

select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。

另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。

poll 
poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。

poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。

另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。

epoll 
直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。

epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。

epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。

另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

 

 

Python select 

Python的select()方法直接调用操作系统的IO接口,它监控sockets,open files, and pipes(所有带fileno()方法的文件句柄)何时变成readable 和writeable, 或者通信错误,select()使得同时监控多个连接变的简单,并且这比写一个长循环来等待和监控多客户端连接要高效,因为select直接通过操作系统提供的C的网络接口进行操作,而不是通过Python的解释器。

注意:Using Python’s file objects with select() works for Unix, but is not supported under Windows.

接下来通过echo server例子要以了解select 是如何通过单进程实现同时处理多个非阻塞的socket连接的

python">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
python keyword">import  python plain">select
python keyword">import  python plain">socket
python keyword">import  python plain">sys
python keyword">import  python plain">Queue
 
python comments"># Create a TCP/IP socket
python plain">server  python keyword">=  python plain">socket.socket(socket.AF_INET, socket.SOCK_STREAM)
python plain">server.setblocking( python value">0 python plain">)
 
python comments"># Bind the socket to the port
python plain">server_address  python keyword">=  python plain">( python string">'localhost' python plain">,  python value">10000 python plain">)
python functions">print  python plain">>>sys.stderr,  python string">'starting up on %s port %s'  python keyword">%  python plain">server_address
python plain">server.bind(server_address)
 
python comments"># Listen for incoming connections
python plain">server.listen( python value">5 python plain">)

 

select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接收所有要发出去的data(outgoing data),第3个监控错误信息,接下来我们需要创建2个列表来包含输入和输出信息来传给select().

python">
# Sockets from which we expect to read
inputs = [ server ] # Sockets to which we expect to write outputs = [ ] 

 

所有客户端的进来的连接和数据将会被server的主循环程序放在上面的list中处理,我们现在的server端需要等待连接可写(writable)之后才能过来,然后接收数据并返回(因此不是在接收到数据之后就立刻返回),因为每个连接要把输入或输出的数据先缓存到queue里,然后再由select取出来再发出去。

Connections are added to and removed from these lists by the server main loop. Since this version of the server is going to wait for a socket to become writable before sending any data (instead of immediately sending the reply), each output connection needs a queue to act as a buffer for the data to be sent through it.

python">
# Outgoing message queues (socket:Queue)
message_queues = {}

The main portion of the server program loops, calling select() to block and wait for network activity.

下面是此程序的主循环,调用select()时会阻塞和等待直到新的连接和数据进来

python">
while inputs:

    # Wait for at least one of the sockets to be ready for processing
    print >>sys.stderr, '\nwaiting for the next event' readable, writable, exceptional = select.select(inputs, outputs, inputs) 

 当你把inputs,outputs,exceptional(这里跟inputs共用)传给select()后,它返回3个新的list,我们上面将他们分别赋值为readable,writable,exceptional, 所有在readable list中的socket连接代表有数据可接收(recv),所有在writable list中的存放着你可以对其进行发送(send)操作的socket连接,当连接通信出现error时会把error写到exceptional列表中。

select() returns three new lists, containing subsets of the contents of the lists passed in. All of the sockets in the readable list have incoming data buffered and available to be read. All of the sockets in the writable list have free space in their buffer and can be written to. The sockets returned in exceptional have had an error (the actual definition of “exceptional condition” depends on the platform).

 

Readable list 中的socket 可以有3种可能状态,第一种是如果这个socket是main "server" socket,它负责监听客户端的连接,如果这个main server socket出现在readable里,那代表这是server端已经ready来接收一个新的连接进来了,为了让这个main server能同时处理多个连接,在下面的代码里,我们把这个main server的socket设置为非阻塞模式。

The “readable” sockets represent three possible cases. If the socket is the main “server” socket, the one being used to listen for connections, then the “readable” condition means it is ready to accept another incoming connection. In addition to adding the new connection to the list of inputs to monitor, this section sets the client socket to not block.

python">
1
2
3
4
5
6
7
8
9
10
11
12
python comments"># Handle inputs
python keyword">for  python plain">s  python keyword">in  python plain">readable:
 
python spaces">     python keyword">if  python plain">s  python keyword">is  python plain">server:
python spaces">         python comments"># A "readable" server socket is ready to accept a connection
python spaces">         python plain">connection, client_address  python keyword">=  python plain">s.accept()
python spaces">         python functions">print  python plain">>>sys.stderr,  python string">'new connection from' python plain">, client_address
python spaces">         python plain">connection.setblocking( python value">0 python plain">)
python spaces">         python plain">inputs.append(connection)
 
python spaces">         python comments"># Give the connection a queue for data we want to send
python spaces">         python plain">message_queues[connection]  python keyword">=  python plain">Queue.Queue()

 

第二种情况是这个socket是已经建立了的连接,它把数据发了过来,这个时候你就可以通过recv()来接收它发过来的数据,然后把接收到的数据放到queue里,这样你就可以把接收到的数据再传回给客户端了。

The next case is an established connection with a client that has sent data. The data is read with recv(), then placed on the queue so it can be sent through the socket and back to the client.

python">
1
2
3
4
5
6
7
8
9
python keyword">else python plain">:
python spaces">      python plain">data  python keyword">=  python plain">s.recv( python value">1024 python plain">)
python spaces">      python keyword">if  python plain">data:
python spaces">          python comments"># A readable client socket has data
python spaces">          python functions">print  python plain">>>sys.stderr,  python string">'received "%s" from %s'  python keyword">%  python plain">(data, s.getpeername())
python spaces">          python plain">message_queues[s].put(data)
python spaces">          python comments"># Add output channel for response
python spaces">          python keyword">if  python plain">s  python keyword">not  python keyword">in  python plain">outputs:
python spaces">              python plain">outputs.append(s)

第三种情况就是这个客户端已经断开了,所以你再通过recv()接收到的数据就为空了,所以这个时候你就可以把这个跟客户端的连接关闭了。

A readable socket without data available is from a client that has disconnected, and the stream is ready to be closed.

python">
1
2
3
4
5
6
7
8
9
10
11
python keyword">else python plain">:
python spaces">     python comments"># Interpret empty result as closed connection
python spaces">     python functions">print  python plain">>>sys.stderr,  python string">'closing' python plain">, client_address,  python string">'after reading no data'
python spaces">     python comments"># Stop listening for input on the connection
python spaces">     python keyword">if  python plain">s  python keyword">in  python plain">outputs:
python spaces">         python plain">outputs.remove(s)   python comments">#既然客户端都断开了,我就不用再给它返回数据了,所以这时候如果这个客户端的连接对象还在outputs列表中,就把它删掉
python spaces">     python plain">inputs.remove(s)     python comments">#inputs中也删除掉
python spaces">     python plain">s.close()            python comments">#把这个连接关闭掉
 
python spaces">     python comments"># Remove message queue
python spaces">     python keyword">del  python plain">message_queues[s]  

  

对于writable list中的socket,也有几种状态,如果这个客户端连接在跟它对应的queue里有数据,就把这个数据取出来再发回给这个客户端,否则就把这个连接从output list中移除,这样下一次循环select()调用时检测到outputs list中没有这个连接,那就会认为这个连接还处于非活动状态

There are fewer cases for the writable connections. If there is data in the queue for a connection, the next message is sent. Otherwise, the connection is removed from the list of output connections so that the next time through the loop select() does not indicate that the socket is ready to send data.

python">
python">
1
2
3
4
5
6
7
8
9
10
11
python comments"># Handle outputs
python keyword">for  python plain">s  python keyword">in  python plain">writable:
python spaces">     python keyword">try python plain">:
python spaces">         python plain">next_msg  python keyword">=  python plain">message_queues[s].get_nowait()
python spaces">     python keyword">except  python plain">Queue.Empty:
python spaces">         python comments"># No messages waiting so stop checking for writability.
python spaces">         python functions">print  python plain">>>sys.stderr,  python string">'output queue for' python plain">, s.getpeername(),  python string">'is empty'
python spaces">         python plain">outputs.remove(s)
python spaces">     python keyword">else python plain">:
python spaces">         python functions">print  python plain">>>sys.stderr,  python string">'sending "%s" to %s'  python keyword">%  python plain">(next_msg, s.getpeername())
python spaces">         python plain">s.send(next_msg)

最后,如果在跟某个socket连接通信过程中出了错误,就把这个连接对象在inputs\outputs\message_queue中都删除,再把连接关闭掉

python">
1
2
3
4
5
6
7
8
9
10
11
python comments"># Handle "exceptional conditions"
python keyword">for  python plain">s  python keyword">in  python plain">exceptional:
python spaces">     python functions">print  python plain">>>sys.stderr,  python string">'handling exceptional condition for' python plain">, s.getpeername()
python spaces">     python comments"># Stop listening for input on the connection
python spaces">     python plain">inputs.remove(s)
python spaces">     python keyword">if  python plain">s  python keyword">in  python plain">outputs:
python spaces">         python plain">outputs.remove(s)
python spaces">     python plain">s.close()
 
python spaces">     python comments"># Remove message queue
python spaces">     python keyword">del  python plain">message_queues[s]

 

客户端

下面的这个是客户端程序展示了如何通过select()对socket进行管理并与多个连接同时进行交互,

The example client program uses two sockets to demonstrate how the server with select() manages multiple connections at the same time. The client starts by connecting each TCP/IP socket to the server.

python">
python">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
python keyword">import  python plain">socket
python keyword">import  python plain">sys
 
python plain">messages  python keyword">=  python plain">[  python string">'This is the message. ' python plain">,
python spaces">              python string">'It will be sent ' python plain">,
python spaces">              python string">'in parts.' python plain">,
python spaces">              python plain">]
python plain">server_address  python keyword">=  python plain">( python string">'localhost' python plain">,  python value">10000 python plain">)
 
python comments"># Create a TCP/IP socket
python plain">socks  python keyword">=  python plain">[ socket.socket(socket.AF_INET, socket.SOCK_STREAM),
python spaces">           python plain">socket.socket(socket.AF_INET, socket.SOCK_STREAM),
python spaces">           python plain">]
 
python comments"># Connect the socket to the port where the server is listening
python functions">print  python plain">>>sys.stderr,  python string">'connecting to %s port %s'  python keyword">%  python plain">server_address
python keyword">for  python plain">s  python keyword">in  python plain">socks:
python spaces">     python plain">s.connect(server_address)

接下来通过循环通过每个socket连接给server发送和接收数据。

 
    

Then it sends one pieces of the message at a time via each socket, and reads all responses available after writing new data.

python">
1
2
3
4
5
6
7
8
9
10
11
12
13
python keyword">for  python plain">message  python keyword">in  python plain">messages:
 
python spaces">     python comments"># Send messages on both sockets
python spaces">     python keyword">for  python plain">s  python keyword">in  python plain">socks:
python spaces">         python functions">print  python plain">>>sys.stderr,  python string">'%s: sending "%s"'  python keyword">%  python plain">(s.getsockname(), message)
python spaces">         python plain">s.send(message)
 
python spaces">     python comments"># Read responses on both sockets
python spaces">     python keyword">for  python plain">s  python keyword">in  python plain">socks:
python spaces">         python plain">data  python keyword">=  python plain">s.recv( python value">1024 python plain">)
python spaces">         python functions">print  python plain">>>sys.stderr,  python string">'%s: received "%s"'  python keyword">%  python plain">(s.getsockname(), data)
python spaces">         python keyword">if  python keyword">not  python plain">data:
python spaces">             python functions">print  python plain">>>sys.stderr,  python string">'closing socket' python plain">, s.getsockname()

 

 

最后服务器端的完整代码如下: 

 

python">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
python comments">#_*_coding:utf-8_*_
python plain">__author__  python keyword">=  python string">'Alex Li'
 
python keyword">import  python plain">select
python keyword">import  python plain">socket
python keyword">import  python plain">sys
python keyword">import  python plain">queue
 
python comments"># Create a TCP/IP socket
python plain">server  python keyword">=  python plain">socket.socket(socket.AF_INET, socket.SOCK_STREAM)
python plain">server.setblocking( python color1">False python plain">)
 
python comments"># Bind the socket to the port
python plain">server_address  python keyword">=  python plain">( python string">'localhost' python plain">,  python value">10000 python plain">)
python functions">print python plain">(sys.stderr,  python string">'starting up on %s port %s'  python keyword">%  python plain">server_address)
python plain">server.bind(server_address)
 
python comments"># Listen for incoming connections
python plain">server.listen( python value">5 python plain">)
 
python comments"># Sockets from which we expect to read
python plain">inputs  python keyword">=  python plain">[ server ]
 
python comments"># Sockets to which we expect to write
python plain">outputs  python keyword">=  python plain">[ ]
 
python plain">message_queues  python keyword">=  python plain">{}
python keyword">while  python plain">inputs:
 
python spaces">     python comments"># Wait for at least one of the sockets to be ready for processing
python spaces">     python functions">print python plain">(  python string">'\nwaiting for the next event' python plain">)
python spaces">     python plain">readable, writable, exceptional  python keyword">=  python plain">select.select(inputs, outputs, inputs)
python spaces">     python comments"># Handle inputs
python spaces">     python keyword">for  python plain">s  python keyword">in  python plain">readable:
 
python spaces">         python keyword">if  python plain">s  python keyword">is  python plain">server:
python spaces">             python comments"># A "readable" server socket is ready to accept a connection
python spaces">             python plain">connection, client_address  python keyword">=  python plain">s.accept()
python spaces">             python functions">print python plain">( python string">'new connection from' python plain">, client_address)
python spaces">             python plain">connection.setblocking( python color1">False python plain">)
python spaces">             python plain">inputs.append(connection)
 
python spaces">             python comments"># Give the connection a queue for data we want to send
python spaces">             python plain">message_queues[connection]  python keyword">=  python plain">queue.Queue()
python spaces">         python keyword">else python plain">:
python spaces">             python plain">data  python keyword">=  python plain">s.recv( python value">1024 python plain">)
python spaces">             python keyword">if  python plain">data:
python spaces">                 python comments"># A readable client socket has data
python spaces">                 python functions">print python plain">(sys.stderr,  python string">'received "%s" from %s'  python keyword">%  python plain">(data, s.getpeername()) )
python spaces">                 python plain">message_queues[s].put(data)
python spaces">                 python comments"># Add output channel for response
python spaces">                 python keyword">if  python plain">s  python keyword">not  python keyword">in  python plain">outputs:
python spaces">                     python plain">outputs.append(s)
python spaces">             python keyword">else python plain">:
python spaces">                 python comments"># Interpret empty result as closed connection
python spaces">                 python functions">print python plain">( python string">'closing' python plain">, client_address,  python string">'after reading no data' python plain">)
python spaces">                 python comments"># Stop listening for input on the connection
python spaces">                 python keyword">if  python plain">s  python keyword">in  python plain">outputs:
python spaces">                     python plain">outputs.remove(s)   python comments">#既然客户端都断开了,我就不用再给它返回数据了,所以这时候如果这个客户端的连接对象还在outputs列表中,就把它删掉
python spaces">                 python plain">inputs.remove(s)     python comments">#inputs中也删除掉
python spaces">                 python plain">s.close()            python comments">#把这个连接关闭掉
 
python spaces">                 python comments"># Remove message queue
python spaces">                 python keyword">del  python plain">message_queues[s]
python spaces">     python comments"># Handle outputs
python spaces">     python keyword">for  python plain">s  python keyword">in  python plain">writable:
python spaces">         python keyword">try python plain">:
python spaces">             python plain">next_msg  python keyword">=  python plain">message_queues[s].get_nowait()
python spaces">         python keyword">except  python plain">queue.Empty:
python spaces">             python comments"># No messages waiting so stop checking for writability.
python spaces">             python functions">print python plain">( python string">'output queue for' python plain">, s.getpeername(),  python string">'is empty' python plain">)
python spaces">             python plain">outputs.remove(s)
python spaces">         python keyword">else python plain">:
python spaces">             python functions">print python plain">(  python string">'sending "%s" to %s'  python keyword">%  python plain">(next_msg, s.getpeername()))
python spaces">             python plain">s.send(next_msg)
python spaces">     python comments"># Handle "exceptional conditions"
python spaces">     python keyword">for  python plain">s  python keyword">in  python plain">exceptional:
python spaces">         python functions">print python plain">( python string">'handling exceptional condition for' python plain">, s.getpeername() )
python spaces">         python comments"># Stop listening for input on the connection
python spaces">         python plain">inputs.remove(s)
python spaces">         python keyword">if  python plain">s  python keyword">in  python plain">outputs:
python spaces">             python plain">outputs.remove(s)
python spaces">         python plain">s.close()
 
python spaces">         python comments"># Remove message queue
python spaces">         python keyword">del  python plain">message_queues[s]

 

  

 

 

 

python">
1
python plain"><strong style python keyword">= python string">"font-family: verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 1.5; " python plain">>客户端的完整代码如下:< python keyword">/ python plain">strong>
python">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
python plain">__author__  python keyword">=  python string">'jieli'
python keyword">import  python plain">socket
python keyword">import  python plain">sys
 
python plain">messages  python keyword">=  python plain">[  python string">'This is the message. ' python plain">,
python spaces">              python string">'It will be sent ' python plain">,
python spaces">              python string">'in parts.' python plain">,
python spaces">              python plain">]
python plain">server_address  python keyword">=  python plain">( python string">'localhost' python plain">,  python value">10000 python plain">)
 
python comments"># Create a TCP/IP socket
python plain">socks  python keyword">=  python plain">[ socket.socket(socket.AF_INET, socket.SOCK_STREAM),
python spaces">           python plain">socket.socket(socket.AF_INET, socket.SOCK_STREAM),
python spaces">           python plain">]
 
python comments"># Connect the socket to the port where the server is listening
python functions">print  python plain">>>sys.stderr,  python string">'connecting to %s port %s'  python keyword">%  python plain">server_address
python keyword">for  python plain">s  python keyword">in  python plain">socks:
python spaces">     python plain">s.connect(server_address)
 
python keyword">for  python plain">message  python keyword">in  python plain">messages:
 
python spaces">     python comments"># Send messages on both sockets
python spaces">     python keyword">for  python plain">s  python keyword">in  python plain">socks:
python spaces">         python functions">print  python plain">>>sys.stderr,  python string">'%s: sending "%s"'  python keyword">%  python plain">(s.getsockname(), message)
python spaces">         python plain">s.send(message)
 
python spaces">     python comments"># Read responses on both sockets
python spaces">     python keyword">for  python plain">s  python keyword">in  python plain">socks:
python spaces">         python plain">data  python keyword">=  python plain">s.recv( python value">1024 python plain">)
python spaces">         python functions">print  python plain">>>sys.stderr,  python string">'%s: received "%s"'  python keyword">%  python plain">(s.getsockname(), data)
python spaces">         python keyword">if  python keyword">not  python plain">data:
python spaces">             python functions">print  python plain">>>sys.stderr,  python string">'closing socket' python plain">, s.getsockname()
python spaces">             python plain">s.close()

Run the server in one window and the client in another. The output will look like this, with different port numbers.

python">
$ python ./select_echo_server.py
starting up on localhost port 10000

waiting for the next event
new connection from ('127.0.0.1', 55821)

waiting for the next event
new connection from ('127.0.0.1', 55822)
received "This is the message. " from ('127.0.0.1', 55821)

waiting for the next event
sending "This is the message. " to ('127.0.0.1', 55821)

waiting for the next event
output queue for ('127.0.0.1', 55821) is empty

waiting for the next event
received "This is the message. " from ('127.0.0.1', 55822)

waiting for the next event
sending "This is the message. " to ('127.0.0.1', 55822)

waiting for the next event
output queue for ('127.0.0.1', 55822) is empty

waiting for the next event
received "It will be sent " from ('127.0.0.1', 55821)
received "It will be sent " from ('127.0.0.1', 55822)

waiting for the next event
sending "It will be sent " to ('127.0.0.1', 55821)
sending "It will be sent " to ('127.0.0.1', 55822)

waiting for the next event
output queue for ('127.0.0.1', 55821) is empty
output queue for ('127.0.0.1', 55822) is empty

waiting for the next event
received "in parts." from ('127.0.0.1', 55821)
received "in parts." from ('127.0.0.1', 55822)

waiting for the next event
sending "in parts." to ('127.0.0.1', 55821)
sending "in parts." to ('127.0.0.1', 55822)

waiting for the next event
output queue for ('127.0.0.1', 55821) is empty
output queue for ('127.0.0.1', 55822) is empty

waiting for the next event
closing ('127.0.0.1', 55822) after reading no data
closing ('127.0.0.1', 55822) after reading no data

waiting for the next event

The client output shows the data being sent and received using both sockets.

python">
$ python ./select_echo_multiclient.py
connecting to localhost port 10000
('127.0.0.1', 55821): sending "This is the message. "
('127.0.0.1', 55822): sending "This is the message. "
('127.0.0.1', 55821): received "This is the message. "
('127.0.0.1', 55822): received "This is the message. "
('127.0.0.1', 55821): sending "It will be sent "
('127.0.0.1', 55822): sending "It will be sent "
('127.0.0.1', 55821): received "It will be sent "
('127.0.0.1', 55822): received "It will be sent "
('127.0.0.1', 55821): sending "in parts."
('127.0.0.1', 55822): sending "in parts."
('127.0.0.1', 55821): received "in parts."
('127.0.0.1', 55822): received "in parts."

转载于:https://www.cnblogs.com/willsen/p/7245494.html


http://www.niftyadmin.cn/n/1559269.html

相关文章

Datax与Sqoop的对比

Sqoop主要特点 1、可以将关系型数据库中的数据导入hdfs、hive或者hbase等hadoop组件中&#xff0c;也可将hadoop组件中的数据导入到关系型数据库中&#xff1b; 2、sqoop在导入导出数据时&#xff0c;充分采用了map-reduce计算框架&#xff0c;根据输入条件生成一个map-reduc…

2021天梯赛全题型训练-2——7-15 长城 (30 分)

正如我们所知&#xff0c;中国古代长城的建造是为了抵御外敌入侵。在长城上&#xff0c;建造了许多烽火台。每个烽火台都监视着一个特定的地区范围。一旦某个地区有外敌入侵&#xff0c;值守在对应烽火台上的士兵就会将敌情通报给周围的烽火台&#xff0c;并迅速接力地传递到总…

DOM操作--你究竟知道多少

前言 DOM常常挂在我们嘴边&#xff0c;但是我们又是否理解它呢&#xff1f;带着这个疑问我开始了 CSS如何工作&#xff1f; 但浏览器显示文档时&#xff0c;它必须将文档的内容与其样式信息结合。分为以下两个阶段处理文档&#xff1a; 浏览器将HTML和CSS转化成DOM&#xff08;…

项目中为什么通常flume和kafka要共同使用

系统架构方面的考虑&#xff1a; (1) flume接kafka可以不用写多余的代码 (2&#xff09;如果系统比较简单&#xff0c;应用场景比较单一&#xff0c;从简化系统的角度考虑&#xff0c;在满足应用需求的情况下可能只使用一个比较好。 (3&#xff09;但是考虑到现有系统业务发展…

2019ACM河北省省赛——Icebound and Sequence

题目描述 Icebound hates math. But Imp loves math. One day, Imp gave icebound a problem. The problem is as follows. For given q,n,p, you need to help icebound to calculate the value of S. 输入描述: The first line contains an integer T, denoting the number …

FOJ-2257 Saya的小熊饼干

这道题呢其实说难不难说简单也不简单(虽然说我做了很久)&#xff0c;重要的就是它的思想---正着做不行就反着做&#xff0c;先求出每个点不被抽到的概率&#xff0c;然后再用1-概率&#xff0c;并全部加起来。#include<iostream> #include<cmath> #include<algo…

2019ACM河北省省赛——Battle of Balls

题目描述 Now that you have a ball of radius r, you want it to go from the bottom boundary of the map to the top boundary of the map (starting and ending points can be considered outside the map, entering the map from the bottom boundary and leaving the map…

WebDriver 命令与操作

&#xff08;1&#xff09;访问一个页面 driver.get("http://www.baidu..com/"); 或者 driver.navigate().to("http://www.baidu.com/); 注意&#xff1a;WebDriver会等待页面加载完成后再继续操作&#xff0c;但是含有AJAX的无法确保AJAX是否已经完全加载&…