參考網站 https://steelkiwi.com/blog/working-tcp-sockets/
(1)第一步驟: 建立SOCKET, 而可用參數包括family
, type
, family可輸入
socket.AF_INET
or socket.AF_INET6
, 而 type 包括了socket.SOCK_STREAM
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
它返回一個socket 物件,而該件有下面的method
bind()
listen()
accept()
connect()
send()
recv()
bind()
, listen()
and accept()
是特定為server 使用, 而 connect()
是特定為client 使用, send()
and recv()
是兩者皆可使用。
簡單的圖示如下
(資料來源:http://www.keil.com/pack/doc/mw6/Network/html/NW_Diagrams.png)
Server 例子
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 50000))
s.listen(1)
conn, addr = s.accept()
while 1: data = conn.recv(1024)
if not data:
break
conn.sendall(data)
conn.close()
client 例子
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 50000))
s.sendall('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
所有的method都是 blocking. 意指socket在讀寫資料時程能等待不能做任何事,可能旳解決方案是使用threads, 但使用threads 程式會較長。所以一個解決方式是使用非同步的方式去處理這問題。最主要概念就是讓OS知道現在socket狀態,socket 是在可讀或可寫狀態。所以下面例子在server 上多一個select method
import select, socket, sys, Queue server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setblocking(0) server.bind(('localhost', 50000)) server.listen(5) inputs = [server] outputs = [] message_queues = {} while inputs: readable, writable, exceptional = select.select( inputs, outputs, inputs) for s in readable: if s is server: connection, client_address = s.accept() connection.setblocking(0) inputs.append(connection) message_queues[connection] = Queue.Queue() else: data = s.recv(1024) if data: message_queues[s].put(data) if s not in outputs: outputs.append(s) else: if s in outputs: outputs.remove(s) inputs.remove(s) s.close() del message_queues[s] for s in writable: try: next_msg = message_queues[s].get_nowait() except Queue.Empty: outputs.remove(s) else: s.send(next_msg) for s in exceptional: inputs.remove(s) if s in outputs: outputs.remove(s) s.close() del message_queues[s]
server.setblocking(0)
. 設定socket 為nonblocking readable, writable, exceptional = select.select(inputs, outputs, inputs) blocking and non-blocking socket最主要的不同是, , and
select.select 要OS求去檢查socekt 是準備去寫或讀或是有例外錯誤,所以需要三個lists去區分那一個socket是預計可讀,可寫,或錯誤。這個method將
block程式(除非有設定timeout)直到有一些socket是準備好的,在此時,這個呼叫將返回三個list,說明socket的狀態。