亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

對python socket編程的初探

stormgens / 3010人閱讀

摘要:對于網(wǎng)絡編程來說,免不了要用到模塊。表示另一端的地址。以上主要是針對流數(shù)據(jù)的編程。對于協(xié)議的數(shù)據(jù),處理略有不同。通過傳入對象調用來監(jiān)聽對象的文件描述符,一旦發(fā)現(xiàn)對象就緒,就通知應用程序進行相應的讀寫操作。

對于python網(wǎng)絡編程來說,免不了要用到socket模塊。下面分享一下個人對python socket的一些理解。

socket編程步驟

服務端創(chuàng)建一個socket,綁定地址和端口,然后監(jiān)聽端口上傳入的連接,一旦有連接進來,就通過accept函數(shù)接收傳入的連接。

客戶端也是創(chuàng)建一個socket。綁定遠程地址和端口,然后建立連接,發(fā)送數(shù)據(jù)。

服務端socket

下面通過一段實例代碼來詳細說明 服務端 socker_server.py

import socket
import sys

HOST = "127.0.0.1"               
PORT = 10000              
s = None
for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC,
                              socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
    af, socktype, proto, canonname, sa = res
    try:
        s = socket.socket(af, socktype, proto)
    except socket.error as msg:
        s = None
        continue
    try:
        s.bind(sa)
        s.listen(5)
    except socket.error as msg:
        s.close()
        s = None
        continue
    break
if s is None:
    print "could not open socket"
    sys.exit(1)
conn, addr = s.accept()
print "Connected by", addr
while 1:
    data = conn.recv(1024)
    if not data: break
    conn.send(data)
conn.close()

首先我們通過socket.getaddrinnfo函數(shù)將host/port轉換成一個包含5元組的序列。這個5元組包含我們創(chuàng)建一個socket連接所需要的所有必要參數(shù)。返回的5元組分別是 (family, sockettype, proto, canonname, sockaddr)

family 地址簇,用與socket()函數(shù)的第一個參數(shù)。主要有以下幾個

socket.AF_UNIX 用與單一機器下的進程通信
socket.AF_INET 用與服務器之間相互通信,通常都用這個。
socket.AF_INET6 支持IPv6
sockettype socket類型,用與socket()函數(shù)的第二個參數(shù),常用的有

socket.SOCK_STREAM 默認,用于TCP協(xié)議
socket.SOCK_DGRAM 用于UDP協(xié)議
proto 協(xié)議,用于socket()函數(shù)的第三個參數(shù)。 getaddrinnfo函數(shù)會根據(jù)地址格式和socket類型,返回合適的協(xié)議

canonname 一個規(guī)范化的host name。

sockaddr 描述了一個socket address .是一個二元組,主要用于bind()和connect()函數(shù)

接下來創(chuàng)建一個socket對象,傳入getaddrinnfo函數(shù)返回的af,sockettype,proto。

 s = socket.socket(af, socktype, proto)

然后綁定我的socket address

s.bind(sa)

開啟監(jiān)聽模式

s.listen(5)

listen函數(shù)會監(jiān)聽連接到socket上的連接,參數(shù)表示在拒絕連接之前系統(tǒng)可以掛起的最大連接隊列數(shù)量為5。這些連接還沒有被accept處理。數(shù)量不能無限大,通常指定5。

一旦我們監(jiān)聽到了連接,就會調用accept函數(shù)接收連接

conn, addr = s.accept()

accept函數(shù)返回一個二元組,conn是一個新的socket對象,用來接收和發(fā)送數(shù)據(jù)。addr表示另一端的socket地址。

接下來我們就可以用conn對象發(fā)送和接收數(shù)據(jù)了

 data = conn.recv(1024) # 接收數(shù)據(jù), 這里指定一次最多接收的字符數(shù)量為1024
 conn.send(data) # 發(fā)送數(shù)據(jù)

這里我們接收到一個連接socket就會停止運行,所以如果要循環(huán)連接的話,將accept函數(shù)放入到一個死循環(huán)里。

客戶端socket

客戶端socket編程相對比較簡單,通過connect和服務端建立連接之后,就可以相互通信了。socket_client.py如下

for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM):
    af, socktype, proto, canonname, sa = res
    try:
        s = socket.socket(af, socktype, proto)
    except socket.error as msg:
        s = None
        continue
    try:
        s.connect(sa)
    except socket.error as msg:
        s.close()
        s = None
        continue
    break
if s is None:
    print "could not open socket"
    sys.exit(1)
s.sendall("Hello, world")
data = s.recv(1024)
s.close()
print "Received", repr(data)

備注: 對于getaddrinfo函數(shù),可以參考下http://baike.baidu.com/link?u... 這個函數(shù)的作用是把協(xié)議相關性安全隱藏在這個底層庫函數(shù)內部。應用程序只要處理由getaddrinfo函數(shù)返回的數(shù)據(jù)即可。

以上主要是針對TCP流數(shù)據(jù)的socket編程。對于UDP協(xié)議的數(shù)據(jù),處理略有不同。譬如發(fā)送接收UDP數(shù)據(jù)包處理函數(shù)為:

socket.sendto(string, flags, address)
socket.recvfrom(bufsize[, flags]) #返回(string, address),string是返回的數(shù)據(jù),address是發(fā)送方的socket地址

其他詳細內容可以參考 http://python.usyiyi.cn/trans...

SocketServer模塊

python中網(wǎng)絡編程除了socket模塊還提供了SocketServer模塊,這一模塊主要是對socket模塊進行了封裝,將socket的對象的創(chuàng)建,綁定,連接,接收,發(fā)送,關閉都封裝在里面,大大簡化了網(wǎng)絡服務的編程。

此模塊提供了以下2個主要的網(wǎng)絡服務類,用于創(chuàng)建相應的套接字流

TCPServer 創(chuàng)建TCP協(xié)議的套接字流

UDPServer 創(chuàng)建UDP協(xié)議的套接字流

我們有了套接字流對象,還需要一個請求處理類。SocketServer模塊提供了請求處理類有BaseRequestHandler,以及它的派生類StreamRequestHandler和DatagramRequestHandler。所以只要繼承這3個類中的一個,然后重寫handle函數(shù),此函數(shù)將用來處理接收到的請求。下面看一個服務端的代碼示例

import SocketServer

class MyTCPHandler(SocketServer.StreamRequestHandler):
   """創(chuàng)建請求處理類,重寫handle方法。此外也可以重寫setup()和finish()來做一些請求處理前和處理后的一些工作"""
    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print "{} wrote:".format(self.client_address[0])
        print self.data
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 10000

    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    # server.shutdown()
    server.serve_forever()  # 一直循環(huán)接收請求
    # server.handle_request() # 只處理一次請求就退出

看著是不是代碼簡單了很多,而且SocketServer模塊內部使用了多路復用IO技術,可以實現(xiàn)更好的連接性能??磗erve_forever函數(shù)的源代碼用到了select模塊。通過傳入socket對象調用select.select()來監(jiān)聽socket對象的文件描述符,一旦發(fā)現(xiàn)socket對象就緒,就通知應用程序進行相應的讀寫操作。源代碼如下:

def serve_forever(self, poll_interval=0.5):
        """Handle one request at a time until shutdown.

        Polls for shutdown every poll_interval seconds. Ignores
        self.timeout. If you need to do periodic tasks, do them in
        another thread.
        """
        self.__is_shut_down.clear()
        try:
            while not self.__shutdown_request:
                # XXX: Consider using another file descriptor or
                # connecting to the socket to wake this up instead of
                # polling. Polling reduces our responsiveness to a
                # shutdown request and wastes cpu at all other times.
                r, w, e = _eintr_retry(select.select, [self], [], [],
                                       poll_interval)
                if self in r:
                    self._handle_request_noblock()
        finally:
            self.__shutdown_request = False
            self.__is_shut_down.set()

即使使用了select技術,TCPServer,UDPServer處理請求仍然是同步的,意味著一個請求處理完,才能處理下一個請求。但SocketServer模塊提供了另外2個類用來支持異步的模式。

ForkingMixIn 利用多進程實現(xiàn)異步

ThreadingMixIn 利用多線程實現(xiàn)異步

看名字就知道使用了mixin模式。而mixin模式可以通過多繼承來實現(xiàn),所以通過對網(wǎng)絡服務類進行多繼承的方式就可以實現(xiàn)異步模式

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

針對ThreadindMixIn,實現(xiàn)異步的原理也就是在內部對每個請求創(chuàng)建一個線程來處理。看源碼

def process_request(self, request, client_address):
        """Start a new thread to process the request."""
        t = threading.Thread(target = self.process_request_thread,
                             args = (request, client_address))
        t.daemon = self.daemon_threads
        t.start()

下面提供一個異步模式的示例

import socket
import threading
import SocketServer

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.current_thread()
        response = "{}: {}".format(cur_thread.name, data)
        self.request.sendall(response)

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    try:
        sock.sendall(message)
        response = sock.recv(1024)
        print "Received: {}".format(response)
    finally:
        sock.close()

if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "localhost", 0

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print "Server loop running in thread:", server_thread.name

    client(ip, port, "Hello World 1")
    client(ip, port, "Hello World 2")
    client(ip, port, "Hello World 3")

    server.shutdown()
    server.server_close()

更多對SocketServer模塊的了解參考https://docs.python.org/2/lib... 本文所使用的示例就來自官網(wǎng)。畢竟官網(wǎng)的例子實在太好了。

以上是本人對socket相關的理解,有什么不當或錯誤之處,還請指出。

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://www.ezyhdfw.cn/yun/44280.html

相關文章

  • python socket編程】—— 1.初探

    摘要:從導入相應函數(shù),即傳入一個上一步中的類,返回對應的網(wǎng)頁內容,具體實現(xiàn)將在后續(xù)講解。后續(xù)只要去處理解析請求和響應部分即可,主程序可以不用再修改。下一篇文章編程解析請求頭 Flask或者其他框架都是封裝的比較完善,我們可以不去關注路由、SESSION等到底是怎么實現(xiàn)的,現(xiàn)在我們使用socket來實現(xiàn)一個帶有注冊、登錄功能的To do網(wǎng)站,這樣能對后端框架了解的稍微更深入一點(當然你也可以直...

    int64 評論0 收藏0
  • python socket編程】—— 2.解析http請求頭

    摘要:請求頭的換行使用的是。編寫一個類,來解析請求的方法路徑和,如下下一篇文章編程響應 前文:【python socket編程】—— 1.初探 在上一篇文章中我們知道,socket.accept()接受的數(shù)據(jù)是請求頭,請求頭格式是這樣的: POST /login HTTP/1.1 Host: 127.0.0.1:1207 User-Agent: Mozilla/5.0 (X11; Ubunt...

    韓冰 評論0 收藏0
  • PHP socket初探 --- 先從一個簡單socket服務器開始

    摘要:原文地址的中文名字叫做套接字,這種東西就是對的封裝。運行結果如下簡單解析一下上述代碼來說明一下服務器的流程首先,根據(jù)協(xié)議族或地址族套接字類型以及具體的的某個協(xié)議來創(chuàng)建一個。很容易受到攻擊,造成拒絕服務。 [原文地址:https://blog.ti-node.com/blog...] socket的中文名字叫做套接字,這種東西就是對TCP/IP的封裝?,F(xiàn)實中的網(wǎng)絡實際上只有四層而已,從上...

    miguel.jiang 評論0 收藏0
  • PHP socket初探 --- 關于IO一些枯燥理論

    摘要:原文地址要想更好了解編程,有一個不可繞過的環(huán)節(jié)就是在中,一切皆文件實際上要文件干啥不就是讀寫么所以,這句話本質就是才是王道用的打開文件關閉文件讀讀寫寫,這叫本地文件在編程中,本質就是網(wǎng)絡所以,在開始進一步的編程前,我們必須先從概念上認識好 [原文地址:https://blog.ti-node.com/blog...] 要想更好了解socket編程,有一個不可繞過的環(huán)節(jié)就是IO.在Lin...

    sf190404 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<