connection, address = socket.accept()
調 用accept方法時,socket會時入“waiting”狀態。客戶請求連接時,方法建立連接並返回服務器。accept方法返回一個含有兩個元素的 元組(connection,address)。第一個元素connection是新的socket對象,服務器必須通過它與客戶通信;第二個元素 address是客戶的Internet地址。
第五步是處理階段,服務器和客戶端通過send和recv方法通信(傳輸 數據)。服務器調用send,並采用字符串形式向客戶發送信息。send方法返回已發送的字符個數。服務器使用recv方法從客戶接收信息。調用recv 時,服務器必須指定一個整數,它對應於可通過本次方法調用來接收的最大數據量。recv方法在接收數據時會進入“blocked”狀態,最后返回一個字符 串,用它表示收到的數據。如果發送的數據量超過了recv所允許的,數據會被截短。多余的數據將緩沖於接收端。以后調用recv時,多余的數據會從緩沖區 刪除(以及自上次調用recv以來,客戶可能發送的其它任何數據)。
傳輸結束,服務器調用socket的close方法關閉連接。
python編寫client的步驟:
舉例:
服務端:
#socket server端
#獲取socket構造及常量
from socket import *
#''代表服務器為localhost
myHost = ''
#在一個非保留端口號上進行監聽
myPort = 50007
#設置一個TCP socket對象
sockobj = socket(AF_INET, SOCK_STREAM)
#綁定它至端口號
sockobj.bind((myHost, myPort))
#監聽,允許5個連結
sockobj.listen(5)
#直到進程結束時才結束循環
while True:
#等待下一個客戶端連結
connection, address = sockobj.accept( )
#連結是一個新的socket
print 'Server connected by', address
while True:
#讀取客戶端套接字的下一行
data = connection.recv(1024)
#如果沒有數量的話,那么跳出循環
if not data: break
#發送一個回復至客戶端
connection.send('Echo=>' + data)
#當socket關閉時eof
connection.close( )
客戶端:
import sys
from socket import *
serverHost = 'localhost'
serverPort = 50007
#發送至服務端的默認文本
message = ['Hello network world']
#如果參數大於1的話,連結的服務端為第一個參數
if len(sys.argv) > 1:
serverHost = sys.argv[1]
#如果參數大於2的話,連結的文字為第二個參數
if len(sys.argv) > 2:
message = sys.argv[2:]
#建立一個tcp/ip套接字對象
sockobj = socket(AF_INET, SOCK_STREAM)
#連結至服務器及端口
sockobj.connect((serverHost, serverPort))
for line in message:
#經過套按字發送line至服務端
sockobj.send(line)
#從服務端接收到的數據,上限為1k
data = sockobj.recv(1024)
#確認他是引用的,是'x'
print 'Client received:', repr(data)
#關閉套接字
sockobj.close( )
參考:
http://blog.sina.com.cn/s/blog_523491650100hikg.html
創建一個socket客戶端
#coding:utf-8 #導入相關模塊 import socket import sys #設置連接請求30S超時 socket.setdefaulttimeout(30) #IPV4協議、字節流(TCP協議) try: s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) except socket.error as e: print 'Socket Error:%s'%(str(e)) sys.exit() print 'Socket Created!' host = 'www.baidu.com' port = 80 #獲取IP地址 try: remote_ip = socket.gethostbyname(host) #此處同PHP中的gethostbyname()函數 except socket.gaierror as e: print 'get %s ip error %s'%(host,str(e)) sys.exit() print 'Ip address of %s is %s'%(host,remote_ip) #連接服務器(SOCK_STREAM/TCP 套接字才有“連接”的概念,一些 Socket 如 UDP、ICMP 和 ARP 沒有“連接”的概念) try: s.connect((remote_ip,port)) except Exception as e: print 'Socket Connect to %s:%s Faile!!Error:%s'%(host,port,str(e)) sys.exit() print 'Socket Connect to %s on ip %s'%(host,remote_ip) #發送數據(根據HTTP/1.1協議) # 請求消息的結構如下 # 請求方法 路徑 HTTP版本\r\n ------>這為請求行 # 請求頭域1: 請求頭域的值1\r\n # 請求頭域2: 請求頭域的值2\r\n # ........................ ------->以上行為請求頭 # 一個空行\r\n -------->頭與主體間的空行 # 請求主體...... -------->請求主體 # ######### #請求行(方法) msg = "GET / HTTP/1.1\r\n" #請求header(HTTP/1.1請求必須包含主機頭域,否則系統會以400狀態碼返回) msg+= "Host: baidu.com\r\n" #空行 msg+= "\r\n" #請求body(由於我們這里是GET請求所以,body沒有) try: #這里也可用send()方法:不同在於sendall在返回前會嘗試發送所有數據 #並且成功時返回是None,而send()則返回發送的字節數量。失敗時都拋出異常。 s.sendall(msg) except Exception as e: print 'Send Failed!' sys.exit() print 'Msg Send Successfully!' #獲取服務器返回的數據 respone = s.recv(4096) #這里還可用recvfrom()、recv_into()等等 print respone #釋放資源 s.close()
輸出:
Socket created
ip address of www.baidu.com is 115.239.210.26
Msg Send successfully!
HTTP/1.1 200 OK
Date: Fri, 21 Feb 2014 05:32:29 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: Keep-Alive
Vary: Accept-Encoding
Set-Cookie: BAIDUID=0D5536687056DF9F5C088AFBE27E42B7:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=7; path=/
Set-Cookie: H_PS_PSSID=4850_1432_5186_5198_4261_5260_4760_5208; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Expires: Fri, 21 Feb 2014 05:32:29 GMT
Cache-Control: private
Server: BWS/1.1
BDPAGETYPE: 1
BDQID: 0x95f7c521930a6c8e
BDUSERID: 0
為什么沒有輸出全部數據呢?看下面的函數:
socket.recv(bufsize[, flags])
Receive data from the socket. The return value is a string representing the data received. The maximum amount of data to be received at once is specified by bufsize. See the Unix manual page recv(2) for the meaning of the optional argument flags; it defaults to zero.
Note
For best match with hardware and network realities, the value of bufsize should be a relatively small power of 2, for example, 4096.
def recv_timeout(the_socket,timeout=2): #make socket non blocking the_socket.setblocking(0) #total data partwise in an array total_data=[]; data=''; #beginning time begin=time.time() while 1: #if you got some data, then break after timeout if total_data and time.time()-begin > timeout: break #if you got no data at all, wait a little longer, twice the timeout elif time.time()-begin > timeout*2: break #recv something try: data = the_socket.recv(8192) if data: total_data.append(data) #change the beginning time for measurement begin=time.time() else: #sleep for sometime to indicate a gap time.sleep(0.1) except: pass #join all parts to make final string return ''.join(total_data)
#coding:utf-8 import socket import sys import time import Queue import threading host = 'localhost' port = 8000 #創建socket對象 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #綁定一個特定地址,端口 try: s.bind((host,port)) except Exception as e : print 'Bind Failed:%s'%(str(e)) sys.exit() print 'Socket bind complete!!' #監聽連接 s.listen(10) #最大連接數10 #創建連接隊列 queue = Queue.Queue() #創建線程 class TaskThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): while 1: t = queue.get() t.send('welecome.....') #接收數據 client_data = t.recv(1024) t.sendall(client_data) #釋放資源 #t.close() #接受連接 while 1: #將連接放入隊列 conn,addr = s.accept() print 'Connected from %s:%s'%(addr[0],str(addr[1])) queue.put(conn) #生成線程池 th = TaskThread() th.setDaemon(True) th.start() queue.join() s.close()
以上例子參考於: http://www.oschina.net/question/12_76126?sort=default&p=2#answers