用Tornado進行API開發(fā)——接收數(shù)據(jù)

用Tornado進行API開發(fā)——接收信息

物聯(lián)網(wǎng)設(shè)備定時向API接口發(fā)送數(shù)據(jù)吩翻,存儲數(shù)據(jù)到數(shù)據(jù)庫寇荧。
接收物聯(lián)網(wǎng)設(shè)備POST的請求
訪問量:每隔10秒同時接收65次連接

解決方案一

使用python官方的http.server里的HTTPServerBaseHTTPRequestHandler
#! /usr/bin/env python3
# -*- coding:UTF-8 -*-
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import json
import cgi
import pandas as pd
import datetime
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
import smtplib
import sys


host = ('',8001)

engine = create_engine('mysql+pymysql://*****:3306/pointgrab_info',pool_size=50,max_overflow=10,pool_timeout =10,poolclass=QueuePool,pool_recycle=-1)


def data_select_sql(areaId):

    sql = " SELECT * FROM pointgrab_count_event_result WHERE capture_area_id ='{0}' ORDER BY id DESC LIMIT 1;".format(areaId)
    df = pd.read_sql_query(sql, engine)
    return df

def data_into_sql(df):

    df.to_sql('pointgrab_count_event_result', engine, index=False, if_exists='append')
    return  True


class TodoHandler(BaseHTTPRequestHandler):


    def do_GET(self):
        self.send_error(415, 'Only post is supported')
        log.error(self.client_address[0]+" - 415 - Only post is supported")

    def do_POST(self):
        ctype, pdict = cgi.parse_header(self.headers['content-type'])
        # print(ctype, pdict)
        token = self.headers['X-Auth-Token']
        # print(token)

        if token == 'token' and ctype == 'application/json':

            path = str(self.path)  # 獲取請求的url
            if path == '/api/counting/':
                # print(path)
                length = int(self.headers['content-length'])  # 獲取除頭部后的請求參數(shù)的長度
                datas = self.rfile.read(length) # 獲取請求參數(shù)數(shù)據(jù),請求數(shù)據(jù)為json字符串
                # print(datas)
                rjson = json.loads(datas.decode())
                # print(rjson,type(rjson))
                lastdata = data_select_sql(rjson['areaId'])
                if rjson['count'] not in lastdata['capture_counts'].values :
                    data_into_sql(rjson)
                    self.send_response(200)
                    self.send_header('Content-type', 'application/json')
                    self.end_headers()
                    self.wfile.write(json.dumps('Counting data is inserted').encode())
                    
                else:
                    self.send_response(200)
                    self.send_header('Content-type', 'application/json')
                    self.end_headers()
                    self.wfile.write(json.dumps('Counting data is duplication').encode())
                    
            else:
                self.send_error(404, "Not Found")
                
        else:
            self.send_error(415, "Only json data is supported.")
            

# 混合類重寫了process_request
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
    pass

def main():

    global server
    server = ThreadingHTTPServer(host, TodoHandler)
    # print(time.asctime(),"Starting server, listen at: %s:%s" % host)
    log.info("Starting server, listen at: %s:%s" % host)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        server.server_close()
        send_mail("Keyboard interrupt received: EXITING")
        # print(time.asctime(), "Keyboard interrupt received: EXITING")
        
    except Exception  as e:
        # print(e)
        server.server_close()
        # print(time.asctime(), "Server Stopped")
        
if __name__ == '__main__':

    main()

出現(xiàn)問題:TCP連接數(shù)暴漲(Linux下查看tcp連接數(shù)及狀態(tài))齐疙,長時間運行后出現(xiàn)程序在運行,端口無法訪問的狀態(tài)
解決方案:并行程序6個即API接口服務(wù)開6個,使用Nginx代理轉(zhuǎn)發(fā)到6個端口莉兰。
upstream pointgrab {
    least_conn;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
    server 127.0.0.1:8004;
    server 127.0.0.1:8005;
    server 127.0.0.1:8006;
    server 127.0.0.1:8007;
    keepalive 16;
}

server {
    listen       8001;
    server_name 127.0.0.1;
    location / {
        proxy_pass   http://pointgrab;
        proxy_set_header        Host    $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
新問題:內(nèi)存占用量比較大
解決方案:定時重啟程序

解決方案二

方案一勉強可以用,但穩(wěn)定性稍差
使用web服務(wù)框架Django礁竞、Flask糖荒、Twisted、Tornado等來開發(fā)
本次采用Tornado來實現(xiàn) Tornado官方文檔
# tornado的GET模捂、POST請求示例
import json
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
import pandas as pd
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
import datetime

#定義端口為8080
define("port", default=8001, help="run on the given port", type=int)
# 數(shù)據(jù)庫連接信息
engine = create_engine('mysql+pymysql://*****:3306/pointgrab_info',pool_size=50,max_overflow=10,pool_timeout =30,poolclass=QueuePool,pool_recycle=-1)

def data_select_sql(areaId):

    sql = " SELECT * FROM pointgrab_count_event_result_copytest WHERE capture_area_id ='{0}' ORDER BY id DESC LIMIT 1;".format(areaId)
    df = pd.read_sql_query(sql, engine)
    return df

def data_into_sql(df):

    df.to_sql('pointgrab_count_event_result_copytest', engine, index=False, if_exists='append')
    return  True


# GET請求
class IndexHandler(tornado.web.RequestHandler):
    # get函數(shù)
    def get(self):
        self.send_error(415, reason="Only post is supported")

# POST請求
# POST請求參數(shù): name, age, city
class CountingHandler(tornado.web.RequestHandler):
    # post函數(shù)

    async def post(self):

        token = self.request.headers['X-Auth-Token']
        ctype = self.request.headers['Content-Type']

        if token == 'token' and ctype == 'application/json':

            path = str(self.request.path)  # 獲取請求的url
            if path == '/api/counting/':

                datas = self.request.body
                rjson = json.loads(datas.decode())
                # print(rjson)
                lastdata = data_select_sql(rjson['areaId'])
                if rjson['count'] not in lastdata['capture_counts'].values :
                    countingdf = counting(rjson)
                    data_into_sql(countingdf)
                    self.set_status(200)
                    self.set_header('Content-type', 'application/json')
                    self.write(json.dumps('Counting data is inserted').encode())
                else:
                    self.set_status(200)
                    self.set_header('Content-type', 'application/json')
                    self.write(json.dumps('Counting data is duplication').encode())


# 主函數(shù)
def main():
    tornado.options.parse_command_line()
    # 定義app
    app = tornado.web.Application(
            handlers=[(r'/', IndexHandler), (r'/api/counting/', CountingHandler)], #網(wǎng)頁路徑控制
          )
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

main()

代碼解釋

實現(xiàn)web.RequestHandler子類捶朵,重載其中的get()和post()

web.Application對象定義路由映射和監(jiān)聽端口

tornado.ioloop.IOLoop.instance().start()啟動IOLoop,該函數(shù)將一直運行且不退出狂男。

HTTPServerRequest常用對象屬性

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末综看,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子岖食,更是在濱河造成了極大的恐慌红碑,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泡垃,死亡現(xiàn)場離奇詭異析珊,居然都是意外死亡,警方通過查閱死者的電腦和手機蔑穴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門忠寻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人存和,你說我怎么就攤上這事奕剃≈月茫” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵纵朋,是天一觀的道長柿顶。 經(jīng)常有香客問我,道長倡蝙,這世上最難降的妖魔是什么九串? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮寺鸥,結(jié)果婚禮上猪钮,老公的妹妹穿的比我還像新娘。我一直安慰自己胆建,他們只是感情好烤低,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著笆载,像睡著了一般扑馁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凉驻,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天腻要,我揣著相機與錄音,去河邊找鬼涝登。 笑死雄家,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的胀滚。 我是一名探鬼主播趟济,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼咽笼!你這毒婦竟也來了顷编?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤剑刑,失蹤者是張志新(化名)和其女友劉穎媳纬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體施掏,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡层宫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了其监。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡限匣,死狀恐怖抖苦,靈堂內(nèi)的尸體忽然破棺而出毁菱,到底是詐尸還是另有隱情,我是刑警寧澤锌历,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布贮庞,位于F島的核電站,受9級特大地震影響究西,放射性物質(zhì)發(fā)生泄漏窗慎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一卤材、第九天 我趴在偏房一處隱蔽的房頂上張望遮斥。 院中可真熱鬧,春花似錦扇丛、人聲如沸术吗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽较屿。三九已至,卻和暖如春卓练,著一層夾襖步出監(jiān)牢的瞬間隘蝎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工襟企, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嘱么,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓整吆,卻偏偏與公主長得像拱撵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子表蝙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 簡介 Tornado龍卷風(fēng)是一個開源的網(wǎng)絡(luò)服務(wù)器框架拴测,它是基于社交聚合網(wǎng)站FriendFeed的實時信息服務(wù)開發(fā)而...
    JunChow520閱讀 54,031評論 4 46
  • 事件驅(qū)動編程 事件驅(qū)動編程是一種網(wǎng)絡(luò)編程范式,程序的執(zhí)行流由外部事件來決定府蛇,特點是包含一個事件循環(huán)集索,當(dāng)外部事件發(fā)生...
    JunChow520閱讀 3,814評論 0 1
  • 1、OC中創(chuàng)建線程的方法是什么汇跨?如果指定在主線程中執(zhí)行代碼务荆?如何延時執(zhí)行代碼∏钏欤【難度系數(shù)★★】 1)創(chuàng)建線程的方法...
    木旁_G閱讀 1,959評論 2 16
  • 一函匕、什么是TCP/IP 網(wǎng)絡(luò)和協(xié)議 1. TCP/IP是一類協(xié)議系統(tǒng),它是一套支持網(wǎng)絡(luò)通信的協(xié)議集合蚪黑。網(wǎng)絡(luò)是計算機...
    karlon的馬甲閱讀 6,540評論 1 24
  • 什么是流Stream呢盅惜? 流Stream是一種抽象的數(shù)據(jù)結(jié)構(gòu)中剩,類似水流當(dāng)在水管中流動時可以從某個地方源源不斷流向另...
    JunChow520閱讀 2,056評論 0 1