close

參考網站 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() 是兩者皆可使用。

簡單的圖示如下

undefined

(資料來源: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最主要的不同是sendrecvconnect and accept能夠不做任何事而返回主程式

select.select 要OS求去檢查socekt 是準備去寫或讀或是有例外錯誤,所以需要三個lists去區分那一個socket是預計可讀,可寫,或錯誤。這個method將block程式(除非有設定timeout)直到有一些socket是準備好的,在此時,這個呼叫將返回三個list,說明socket的狀態。

 
arrow
arrow
    全站熱搜

    stanley 發表在 痞客邦 留言(0) 人氣()