最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

結(jié)合Python的SimpleHTTPServer源碼來解析socket通信

 更新時(shí)間:2016年06月27日 16:27:23   作者:人世間  
SimpleHTTPServer是Python中一個(gè)現(xiàn)成的HTTP服務(wù)器例子,本文我們將結(jié)合Python的SimpleHTTPServer源碼來解析socket通信,我們先來看一下socket的基本概念:

何謂socket
計(jì)算機(jī),顧名思義即是用來做計(jì)算。因而也需要輸入和輸出,輸入需要計(jì)算的條件,輸出計(jì)算結(jié)果。這些輸入輸出可以抽象為I/O(input output)。

Unix的計(jì)算機(jī)處理IO是通過文件的抽象。計(jì)算機(jī)不同的進(jìn)程之間也有輸入輸出,也就是通信。因此這這個(gè)通信也是通過文件的抽象文件描述符來進(jìn)行。

在同一臺(tái)計(jì)算機(jī),進(jìn)程之間可以這樣通信,如果是不同的計(jì)算機(jī)呢?網(wǎng)絡(luò)上不同的計(jì)算機(jī),也可以通信,那么就得使用網(wǎng)絡(luò)套接字(socket)。socket就是在不同計(jì)算機(jī)之間進(jìn)行通信的一個(gè)抽象。他工作于TCP/IP協(xié)議中應(yīng)用層和傳輸層之間的一個(gè)抽象。如下圖:

2016627161931394.jpg (542×476)

服務(wù)器通信
socket保證了不同計(jì)算機(jī)之間的通信,也就是網(wǎng)絡(luò)通信。對(duì)于網(wǎng)站,通信模型是客戶端服務(wù)器之間的通信。兩個(gè)端都建立一個(gè)socket對(duì)象,然后通過socket對(duì)象對(duì)數(shù)據(jù)進(jìn)行傳輸。通常服務(wù)器處于一個(gè)無(wú)線循環(huán),等待客戶端連接:

2016627162000798.jpg (478×491)

socket 通信實(shí)例
socket接口是操作系統(tǒng)提供的,調(diào)用操作系統(tǒng)的接口。當(dāng)然高級(jí)語(yǔ)言一般也封裝了好用的函數(shù)接口,下面用python代碼寫一個(gè)簡(jiǎn)單的socket服務(wù)端例子:

server.py

import socket

HOST = 'localhost'   # 服務(wù)器主機(jī)地址
PORT = 5000       # 服務(wù)器監(jiān)聽端口
BUFFER_SIZE = 2048   # 讀取數(shù)據(jù)大小

# 創(chuàng)建一個(gè)套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
# 綁定主機(jī)和端口
sock.bind((HOST, PORT))
# 開啟socket監(jiān)聽
sock.listen(5)


print 'Server start, listening {}'.format(PORT)


while True:
  # 建立連接,連接為建立的時(shí)候阻塞
  conn, addr = sock.accept()
  while True:
    # 讀取數(shù)據(jù),數(shù)據(jù)還沒到來阻塞
    data = conn.recv(BUFFER_SIZE)
    if len(data):
      print 'Server Recv Data: {}'.format(data)
      conn.send(data)
      print 'Server Send Data: {}'.format(data)
    else:
      print 'Server Recv Over'
      break
  conn.close()
sock.close()

client.py

import socket

HOST = 'localhost'
PORT = 5000
BUFFER_SIZE = 1024

# 創(chuàng)建客戶端套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 連接到服務(wù)器
sock.connect((HOST, PORT))

try:
  message = "Hello"
  # 發(fā)起數(shù)據(jù)給服務(wù)器
  sock.sendall(message)
  amount_received = 0
  amount_expected = len(message)
  while amount_received < amount_expected:
    # 接收服務(wù)器返回的數(shù)據(jù)
    data = sock.recv(10)
    amount_received += len(data)
    print 'Client Received: {}'.format(data)

except socket.errno, e:
  print 'Socket error: {}'.format(e)
except Exception, e:
  print 'Other exception: %s'.format(e)
finally:
  print 'Closing connection to the server'
  sock.close()

TCP 三次握手
python代碼寫套接字很簡(jiǎn)單。傳說的TCP三次握手又是如何體現(xiàn)的呢?什么是三次握手呢?

第一握:首先客戶端發(fā)送一個(gè)syn,請(qǐng)求連接,
第二握:服務(wù)器收到之后確認(rèn),并發(fā)送一個(gè) syn ack應(yīng)答
第三握:客戶端接收到服務(wù)器發(fā)來的應(yīng)答之后再給服務(wù)器發(fā)送建立連接的確定。
用下面的比喻就是

C:約么?

S:約

C:好的

約會(huì)
這樣就建立了一個(gè)TCP連接會(huì)話。如果是要斷開連接,大致過程是:

2016627162110796.png (416×209)

上圖也很清晰的表明了三次握手的socket具體過程。

  • 客戶端socket對(duì)象connect調(diào)用之后進(jìn)行阻塞,此過程發(fā)送了一個(gè)syn。
  • 服務(wù)器socket對(duì)象調(diào)用accept函數(shù)之后阻塞,直到客戶端發(fā)送來的syn,然后發(fā)送syn和ack應(yīng)答
  • 客戶端socket對(duì)象收到服務(wù)端發(fā)送的應(yīng)答之后,再發(fā)送一個(gè)ack給服務(wù)器,并返回connect調(diào)用,建立連接。
  • 服務(wù)器socket對(duì)象接受客戶端最后一次握手確定ack返回accept函數(shù),建立連接。

至此,客戶端和服務(wù)器的socket通信連接建立完成,剩下的就是兩個(gè)端的連接對(duì)象收發(fā)數(shù)據(jù),從而完成網(wǎng)絡(luò)通信。


SimpleHTTPServer
構(gòu)建一個(gè)簡(jiǎn)單的HTTP服務(wù),需要繼承HTTPServer,同時(shí)requesthandler也需要繼承BaseHTTPRequestHandler。python已經(jīng)實(shí)現(xiàn)了一個(gè)例子,那就是SimpleHTTPServer。因此分析SimpleHTTPServer來查看如何使用前面的一些類構(gòu)建http服務(wù)。

曾經(jīng)為了表示python的簡(jiǎn)潔優(yōu)雅,經(jīng)常會(huì)舉這樣的例子,python可以一行代碼開啟一個(gè)服務(wù)器。

$ python -m SimpleHTTPServer

這里的SimpleHTTPServer就是實(shí)現(xiàn)了HTTPServer的模塊。

SimpleHTTPServer通過調(diào)用BaseHTTPServer模塊的test方法做為入口。

def test(HandlerClass = SimpleHTTPRequestHandler,
     ServerClass = BaseHTTPServer.HTTPServer):
  BaseHTTPServer.test(HandlerClass, ServerClass)

test方法做了兩件事,第一件就是使用HTTPServer接受一個(gè)監(jiān)聽地址和requestClass參數(shù),創(chuàng)建了一個(gè)實(shí)例對(duì)象,調(diào)用server_forever方法開啟服務(wù)。

1.SimpleHTTPRequestHandler
根據(jù)之前的分析,使用httpserver的服務(wù),我們只需要繼續(xù)BaseHTTPRequestHandler,并提供自省的method方法即可。

class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
  server_version = "SimpleHTTP/" + __version__

  def do_GET(self):
    f = self.send_head()
    if f:
      self.copyfile(f, self.wfile)
      f.close()

  def do_HEAD(self):
    f = self.send_head()
    if f:
      f.close()

do_GET 和 do_HEAD 分別實(shí)現(xiàn)了http的get請(qǐng)求和head請(qǐng)求的處理。他們調(diào)用send_head方法:

   

def send_head(self):

    path = self.translate_path(self.path)
    f = None
    if os.path.isdir(path):
      if not self.path.endswith('/'):
        self.send_response(301)
        self.send_header("Location", self.path + "/")
        self.end_headers()
        return None
      for index in "index.html", "index.htm":
        index = os.path.join(path, index)
        if os.path.exists(index):
          path = index
          break
      else:
        return self.list_directory(path)
    ctype = self.guess_type(path)
    try:
      f = open(path, 'rb')
    except IOError:
      self.send_error(404, "File not found")
      return None
    self.send_response(200)
    self.send_header("Content-type", ctype)
    fs = os.fstat(f.fileno())
    self.send_header("Content-Length", str(fs[6]))
    self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
    self.end_headers()
    return f

send_head 方法通過uri的path分析得到客戶請(qǐng)求的網(wǎng)路路徑。構(gòu)造head的mime元信息并發(fā)送到客戶端,然后返回一個(gè)打開path的文件句柄。

2.copyfile
do_GET的下一步就是通過 copyfile方法,將客戶請(qǐng)求的path的文件數(shù)據(jù)寫入到緩沖可寫文件中,發(fā)送給客戶端。

3.list_directory
SimpleHTTPServer模塊還提供了list_directory方法,用于響應(yīng)path是一個(gè)目錄,而不是文件的情況。

def list_directory(self, path):
  try:
    list = os.listdir(path)
  except os.error:
    self.send_error(404, "No permission to list directory")
    return None
  list.sort(key=lambda a: a.lower())
  f = StringIO()
  displaypath = cgi.escape(urllib.unquote(self.path))
  f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
  f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
  f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
  f.write("<hr>\n<ul>\n")
  for name in list:
    fullname = os.path.join(path, name)
    displayname = linkname = name
    # Append / for directories or @ for symbolic links
    if os.path.isdir(fullname):
      displayname = name + "/"
      linkname = name + "/"
    if os.path.islink(fullname):
      displayname = name + "@"
      # Note: a link to a directory displays with @ and links with /
    f.write('<li><a href="%s">%s</a>\n'
        % (urllib.quote(linkname), cgi.escape(displayname)))
  f.write("</ul>\n<hr>\n</body>\n</html>\n")
  length = f.tell()
  f.seek(0)
  self.send_response(200)
  encoding = sys.getfilesystemencoding()
  self.send_header("Content-type", "text/html; charset=%s" % encoding)
  self.send_header("Content-Length", str(length))
  self.end_headers()
  return f

由此可見,處理客戶端的請(qǐng)求,只需要使用 send_reponse, send_header 和 end_headers ,就能向客戶端發(fā)送reponse。

4.自定義http服務(wù)
定義一個(gè)CustomHTTPRequestHadnler繼承自BaseHTTPRequestHandler。在其內(nèi)實(shí)現(xiàn)do_GET 方法來處理get請(qǐng)求。

然后再定義一個(gè)CustomHTTPServer繼承自HTTPServer,它接受CustomHTTPRequestHadnler作為自己的handler。簡(jiǎn)單的代碼如下:

# -*- coding: utf-8 -*-

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer


class CustomHTTPRequestHandler(BaseHTTPRequestHandler):
  def do_GET(self):
    self.send_response(200)
    self.send_header('Content-type', 'text/html')
    self.end_headers()
    self.wfile.write("hello world\r\n")


class CustomHTTPServer(HTTPServer):
  def __init__(self, host, port):
    HTTPServer.__init__(self, (host, port), CustomHTTPRequestHandler)


def main():
  server = CustomHTTPServer('127.0.0.1', 8000)
  server.serve_forever()


if __name__ == '__main__':
  main()

使用curl訪問可以得到

➜ ~ curl http://127.0.0.1:8000
hello world
➜ ~

控制臺(tái)會(huì)打出訪問的log。

127.0.0.1 - - [01/Jun/2015 11:42:33] "GET / HTTP/1.1" 200 -

從socket的建立,select的IO模式,再到Server和Handler的組合構(gòu)建服務(wù)。我們已經(jīng)熟悉了python的基本網(wǎng)絡(luò)編程。python的web開發(fā)中,更多是使用WSGI協(xié)議。實(shí)現(xiàn)該協(xié)議的還有 uWSGI和gunicorn等庫(kù)。相比那些庫(kù),python內(nèi)部提供了一個(gè)wsgiref模塊,實(shí)現(xiàn)了一個(gè)簡(jiǎn)單wsgi服務(wù)--simple_server。

接下來將會(huì)通過分析simple_server,更好的掌握WSGI協(xié)議。

相關(guān)文章

  • python進(jìn)行文件對(duì)比的方法

    python進(jìn)行文件對(duì)比的方法

    在本篇內(nèi)容里小編給分享了關(guān)于python進(jìn)行文件對(duì)比的方法和步驟,需要的朋友們可以學(xué)習(xí)下。
    2018-12-12
  • Python中scatter散點(diǎn)圖及顏色整理大全

    Python中scatter散點(diǎn)圖及顏色整理大全

    python自帶的scatter函數(shù)參數(shù)中顏色和大小可以輸入列表進(jìn)行控制,即可以讓不同的點(diǎn)有不同的顏色和大小,下面這篇文章主要給大家介紹了關(guān)于Python中scatter散點(diǎn)圖及顏色整理大全的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Python使用Supervisor來管理進(jìn)程的方法

    Python使用Supervisor來管理進(jìn)程的方法

    這篇文章主要介紹了Python使用Supervisor來管理進(jìn)程的方法,涉及Supervisor的相關(guān)使用技巧,需要的朋友可以參考下
    2015-05-05
  • Pyecharts 動(dòng)態(tài)地圖 geo()和map()的安裝與用法詳解

    Pyecharts 動(dòng)態(tài)地圖 geo()和map()的安裝與用法詳解

    這篇文章主要介紹了Pyecharts 動(dòng)態(tài)地圖 geo()和map()的安裝與用法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • 詳解Python描述符的工作原理

    詳解Python描述符的工作原理

    在 Python 開發(fā)中,你可能聽說過「描述符」這個(gè)概念,由于我們很少直接使用它,所以大部分開發(fā)人員并不了解它的原理. 但作為熟練使用 Python,想要進(jìn)階的你,建議還是了解一下描述符的原理,這也便于你更深層次地理解 Python 的設(shè)計(jì)思想,需要的朋友可以參考下
    2021-06-06
  • Django 批量插入數(shù)據(jù)的實(shí)現(xiàn)方法

    Django 批量插入數(shù)據(jù)的實(shí)現(xiàn)方法

    這篇文章主要介紹了Django 批量插入數(shù)據(jù)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Tensorflow:轉(zhuǎn)置函數(shù) transpose的使用詳解

    Tensorflow:轉(zhuǎn)置函數(shù) transpose的使用詳解

    今天小編就為大家分享一篇Tensorflow:轉(zhuǎn)置函數(shù) transpose的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • python爬取酷狗音樂排行榜

    python爬取酷狗音樂排行榜

    這篇文章主要為大家詳細(xì)介紹了python爬取酷狗音樂排行榜,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • Python利用代碼計(jì)算2個(gè)坐標(biāo)之間的距離

    Python利用代碼計(jì)算2個(gè)坐標(biāo)之間的距離

    這篇文章主要介紹了Python利用代碼計(jì)算2個(gè)坐標(biāo)之間的距離,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • python實(shí)現(xiàn)簡(jiǎn)單聊天室功能 可以私聊

    python實(shí)現(xiàn)簡(jiǎn)單聊天室功能 可以私聊

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡(jiǎn)單聊天室功能,可以進(jìn)行私聊,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07

最新評(píng)論

文登市| 沙湾县| 旺苍县| 梅州市| 旺苍县| 天祝| 东乡| 铜山县| 南充市| 望江县| 和田市| 双城市| 辉县市| 南召县| 常德市| 富川| 枝江市| 丰宁| 吴江市| 阿克| 资溪县| 南华县| 淮滨县| 江安县| 龙江县| 玉山县| 陈巴尔虎旗| 错那县| 永嘉县| 青岛市| 苍溪县| 武夷山市| 古蔺县| 东至县| 三原县| 吉林省| 鹤峰县| 通江县| 寻乌县| 兰坪| 仁布县|