服務(wù)端:
importselect
importsocket
importsys
importQueue
# Create a TCP/IP socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)
# Bind the socket to the port
server_address = ('localhost',9999)
print(sys.stderr,'starting up on %s port %s'% server_address)
server.bind(server_address)
# Listen for incoming connections
server.listen(5)
# Sockets from which we expect to read
inputs = [server]
# Sockets to which we expect to write
outputs = []
message_queues = {}
whileinputs:
# Wait for at least one of the sockets to be ready for processing
print('\nwaiting for the next event')
readable, writable, exceptional = select.select(inputs, outputs, inputs)
# Handle inputs
forsinreadable:
ifsisserver:
# A "readable" server socket is ready to accept a connection
connection, client_address = s.accept()
print('new connection from', client_address)
connection.setblocking(False)
inputs.append(connection)
# Give the connection a queue for data we want to send
message_queues[connection] = Queue.Queue()
else:
data = s.recv(1024)
ifdata:
# A readable client socket has data
print(sys.stderr,'received "%s" from %s'% (data, s.getpeername()))
message_queues[s].put(data)
# Add output channel for response
ifsnot inoutputs:
outputs.append(s)
else:
# Interpret empty result as closed connection
print('closing', client_address,'after reading no data')
# Stop listening for input on the connection
ifsinoutputs:
outputs.remove(s)# 既然客戶端都斷開了,我就不用再給它返回數(shù)據(jù)了捎迫,所以這時候如果這個客戶端的連接對象還在outputs列表中晃酒,就把它刪掉
inputs.remove(s)# inputs中也刪除掉
s.close()# 把這個連接關(guān)閉掉
# Remove message queue
delmessage_queues[s]
# Handle outputs
forsinwritable:
try:
next_msg = message_queues[s].get_nowait()
exceptQueue.Empty:
# No messages waiting so stop checking for writability.
print('output queue for', s.getpeername(),'is empty')
outputs.remove(s)
else:
print('sending "%s" to %s'% (next_msg, s.getpeername()))
s.send(next_msg)
# Handle "exceptional conditions"
forsinexceptional:
print('handling exceptional condition for', s.getpeername())
# Stop listening for input on the connection
inputs.remove(s)
ifsinoutputs:
outputs.remove(s)
s.close()
# Remove message queue
delmessage_queues[s]
客戶端:
importsocket
importsys
messages = ['This is the message. ',
'It will be sent ',
'in parts.',
]
server_address = ('localhost',9999)
# Create a TCP/IP socket
socks = [socket.socket(socket.AF_INET, socket.SOCK_STREAM),
socket.socket(socket.AF_INET, socket.SOCK_STREAM),
]
# Connect the socket to the port where the server is listening
print>> sys.stderr,'connecting to %s port %s'% server_address
forsinsocks:
s.connect(server_address)
formessageinmessages:
# Send messages on both sockets
forsinsocks:
print>> sys.stderr,'%s: sending "%s"'% (s.getsockname(), message)
s.send(message)
# Read responses on both sockets
forsinsocks:
data = s.recv(1024)
print>> sys.stderr,'%s: received "%s"'% (s.getsockname(), data)
if notdata:
print>> sys.stderr,'closing socket', s.getsockname()
s.close()
原文:http://pymotw.com/2/select/
經(jīng)過實驗,其實windows也是支持的窄绒。
注:
select()方法接收并監(jiān)控3個通信列表贝次, 第一個是所有的輸入的data,就是指外部發(fā)過來的數(shù)據(jù),第2個是監(jiān)控和接收所有要發(fā)出去的data(outgoing data),第3個監(jiān)控錯誤信息彰导。
當(dāng)你把inputs,outputs,exceptional(這里跟inputs共用)傳給select()后蛔翅,它返回3個新的list,我們上面將他們分別賦值為readable,writable,exceptional, 所有在readable list中的socket連接代表有數(shù)據(jù)可接收(recv),所有在writable list中的存放著你可以對其進行發(fā)送(send)操作的socket連接螺戳,當(dāng)連接通信出現(xiàn)error時會把error寫到exceptional列表中搁宾。
Readable list 中的socket 可以有3種可能狀態(tài),第一種是如果這個socket是main "server" socket,它負(fù)責(zé)監(jiān)聽客戶端的連接倔幼,如果這個main server socket出現(xiàn)在readable里盖腿,那代表這是server端已經(jīng)ready來接收一個新的連接進來了,為了讓這個main server能同時處理多個連接损同,在下面的代碼里翩腐,我們把這個main server的socket設(shè)置為非阻塞模式。
第二種情況是這個socket是已經(jīng)建立了的連接膏燃,它把數(shù)據(jù)發(fā)了過來茂卦,這個時候你就可以通過recv()來接收它發(fā)過來的數(shù)據(jù),然后把接收到的數(shù)據(jù)放到queue里组哩,這樣你就可以把接收到的數(shù)據(jù)再傳回給客戶端了等龙。
第三種情況就是這個客戶端已經(jīng)斷開了,所以你再通過recv()接收到的數(shù)據(jù)就為空了伶贰,所以這個時候你就可以把這個跟客戶端的連接關(guān)閉了蛛砰。
對于writable list中的socket,也有幾種狀態(tài)黍衙,如果這個客戶端連接在跟它對應(yīng)的queue里有數(shù)據(jù)泥畅,就把這個數(shù)據(jù)取出來再發(fā)回給這個客戶端,否則就把這個連接從output list中移除琅翻,這樣下一次循環(huán)select()調(diào)用時檢測到outputs list中沒有這個連接位仁,那就會認(rèn)為這個連接還處于非活動狀態(tài)
最后,如果在跟某個socket連接通信過程中出了錯誤方椎,就把這個連接對象在inputs\outputs\message_queue中都刪除聂抢,再把連接關(guān)閉掉
注解轉(zhuǎn)自http://www.cnblogs.com/alex3714/p/4372426.html。
部分源碼有問題我已自行修改辩尊。