早先對於python服務器的理解不夠充分
對於這門語言的理解一直只處於前端網頁的制作與后端數據處理方面
因此對於python服務器的搭建幾乎處於空白階段
對此我表示需要深刻的惡補
因此從頭學習python服務器的搭建
結果沒想到python服務器處理tcp請求也是使用socket的方式
因此對於我的學習來說還算是比較順利
1 p_port = ('192.168.7.11', 9999) 2 web = socket.socket() 3 web.bind(ip_port) 4 web.listen(5) 5 6 while True: 7 print 'I am waiting for the client' 8 conn, addr = web.accept() 9 # thread = threading.Thread(target=jonnys, args=(conn, addr)) 10 11 data = conn.recv(1024) 12 print data 13 conn.sendall(str('<h1>welcome nginx</h1>')) 14 conn.close()
以上是簡單的服務器
附使用簡單客戶端
import socket ip_port = ('192.168.7.11', 9999) sk = socket.socket() sk.connect(ip_port) sk.sendall('haha douyu\n') sk.sendall('you like join this\n') server_reply = sk.recv(1024) # server_reply_three = sk.recv(1024) print server_reply # print server_reply_three # sk.sendall('join this\n') # server_reply_two = sk.recv(1024) # print server_reply_two sk.close()
使用ThreadingTCPServer, StreamRequestHandler來實現多線程服務器處理
但是有一個小BUG需要解決
from SocketServer import ThreadingTCPServer, StreamRequestHandler import traceback class MyStreamRequestHandlerr(StreamRequestHandler): """ #StreamRequestHandler,並重寫handle方法 #(StreamRequestHandler繼承自BaseRequestHandler) """ def handle(self): while True: #客戶端主動斷開連接時,self.rfile.readline()會拋出異常 try: #self.rfile類型是socket._fileobject,讀寫模式是"rb",方法有 #read,readline,readlines,write(data),writelines(list),close,flush data = self.rfile.readline().strip() # if data == '\'\'': # print data print "receive from (%r):%r" % (self.client_address, data) # data = self.request.recev(1024).strip #self.client_address是客戶端的連接(host, port)的元組) #self.wfile類型是socket._fileobject,讀寫模式是"wb" self.wfile.write(data.upper()) except: traceback.print_exc() break if __name__ == "__main__": #telnet 127.0.0.1 9999 host = "" #主機名,可以是ip,像localhost的主機名,或"" port = 9999 #端口 addr = (host, port) #ThreadingTCPServer從ThreadingMixIn和TCPServer繼承 #class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass server = ThreadingTCPServer(addr, MyStreamRequestHandlerr) #啟動服務監聽 server.serve_forever()
當客戶端主動關閉套接字時
服務器會出現死循環產生子線程來讀取空的信息
從而使服務器崩潰
因此誕生第三個版本

# -*- coding: UTF-8 -*- import socket import threading, getopt, sys, string opts, args = getopt.getopt(sys.argv[1:], "hp:l:", ["help", "port=", "list="]) #設置默認的最大連接數和端口號,在沒有使用命令傳入參數的時候將使用默認的值 list=50 port=9999 def usage(): print """ -h --help print the help -l --list Maximum number of connections -p --port To monitor the port number """ for op, value in opts: if op in ("-l","--list"): list = string.atol(value) elif op in ("-p","--port"): port = string.atol(value) elif op in ("-h"): usage() sys.exit() def jonnyS(client, address): try: #設置超時時間 client.settimeout(500) #接收數據的大小 buf = client.recv(2048) print buf #將接收到的信息原樣的返回到客戶端中 client.send(buf) #超時后顯示退出 except socket.timeout: print 'time out' #關閉與客戶端的連接 client.close() def main(): #創建socket對象。調用socket構造函數 #AF_INET為ip地址族,SOCK_STREAM為流套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #將socket綁定到指定地址,第一個參數為ip地址,第二個參數為端口號 sock.bind(('192.168.7.11', port)) #設置最多連接數量 sock.listen(list) while True: #服務器套接字通過socket的accept方法等待客戶請求一個連接 client, address = sock.accept() thread = threading.Thread(target=jonnyS, args=(client, address)) thread.start() if __name__ == '__main__': main()
這個版本當服務器與客戶端完成通信之后會由服務器關閉套接字
還包括延時功能
因此不會有第二個程序的bug