溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

10.python網絡編程(startin part 1)

發布時間:2020-04-07 15:46:56 來源:網絡 閱讀:943 作者:蘇浩智 欄目:建站服務器

一.什么是socket?

socket就是為了實現C/S架構而生的,socket位于應用層和傳輸層之間,是傳輸層和應用層之間的一組接口,它把復雜的TCP/IP協議族隱藏在Socket接口后面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議,所以,我們無需深入理解tcp/udp協議,socket已經為我們封裝好了,我們只需要遵循socket的規定去編程,寫出的程序自然就是遵循tcp/udp標準的。

也有人將socket說成ip+port,ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這臺機器上的一個應用程序,ip地址是配置到網卡上的,而port是應用程序開啟的,ip與port的綁定就標識了互聯網中獨一無二的一個應用程序。

補充:有人會把socket和程序的pid弄混,程序的pid是同一臺機器上不同進程或者線程的標識。


二.socket種類。

  1. 基于文件型套接字。

    AF_UNIX:基于文件型的套接字,就是通過底層的文件系統來取數據,兩個套接字進程運行在同一臺機器,可以通過訪問同一個文件系統來實現兩個程序之間的通信。

  2. 基于網絡型套接字。

三.socket工作流程。

10.python網絡編程(startin part 1)

tcp服務端建立連接流程:

socket()實例化出一個套接字對象→bind()綁定ip地址和端口→listen()開始監聽之前綁定的ip地址和端口→accept()開始被動接收tcp客戶端發來的連接,會一直等連接的到來(如果沒有連接,就會一直等,直到有客戶端連過來。

tcp客戶端建立連接流程:

socket()客戶端也初始化一個套接字對象→connect()主動去連接服務端(主動初始化與tcp服務器的連接)如果連接成功,客戶端和服務器之間就可以互相收發數據了。(其實connect就相當于去回應服務端的accept,服務端的accept一直在等待客戶端去connect)

客戶端發送數據請求,服務器端接收請求并處理請求,然后把回應數據發送給客戶端,客戶端讀取數據,最后關閉連接,一次交互結束。



四.socket模塊的用法。

import socket

socket.socket(socket_family,socket_type,protocal=0)

socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默認值為 0。

獲取tcp/ip套接字

tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

獲取udp/ip套接字

udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

由于 socket 模塊中有太多的屬性。我們在這里破例使用了'from module import *'語句。使用 'from socket import *',我們就把 socket 模塊里的所有屬性都帶到我們的命名空間里了,這樣能 大幅減短我們的代碼。

例如tcpSock = socket(AF_INET, SOCK_STREAM)


服務端常用專屬套接字方法:

s.bind():綁定(主機,端口號)到套接字。

s.listen():開始進行tcp監聽。#listen方法中可以指定一個backlog參數,這個參數用于設置tcp連接池的大?。P于tcp連接池和三次握手的知識后面會做補充。)

s.accept():被動接受TCP客戶的連接,(阻塞式)等待連接的到來。


客戶端常用專屬套接字方法:

s.connect():主動初始化TCP服務器連接

s.connect_ex() : connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常。


客戶端和服務端共同具有的常用套接字方法:

s.recv():接收tcp數據。#需要指定每次收多少字節。

s.send():  發送tcp數據,#發送TCP數據(send在待發送數據量大于對端緩存區剩余空間時,數據丟失,不會發完)

s.sendall(): 發送tcp數據,發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大于對端緩存區剩余空間時,數據不丟失,循環調用send直到發完)(個人分析,本質上是調用了循環)

s.recvfrom():接收UDP數據

s.sendto() : 發送UDP數據

s.getpeername() : 連接到當前套接字的遠端的地址

s.getsockname()  :   當前套接字的地址

s.getsockopt() :返回指定套接字的參數

s.setsockopt() : 設置指定套接字的參數

s.close() :關閉套接字


五.socket用法示例。

服務端:

#!/usr/bin/python2.7

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

import socket

address_and_port = ('127.0.0.1',8888)

s1 = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)

s1.bind(address_and_port)

s1.listen(3)

conn,addr = s1.accept() #執行了socket的accept方法后,開始阻塞,等待客戶端的連接.

#執行了accept方法后,會返回一個元祖,這個元祖里面包含了一個客戶端的連接對象,還有客戶端的ip地址和端口.

while True:

    data = conn.recv(1024) #用于接收tcp數據,后面的1024表示,recv一次最多可以接收1024字節.(執行到recv,如果對端沒有發來數據,或者內容為空,程序會阻塞住,不繼續向下執行。)

    print data

    conn.send(data.upper())

conn.close() #關閉與客戶端的連接

s1.close()  #關閉服務端套接字連接


客戶端:

#!/usr/bin/python2.7

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

import socket

s1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s1.connect(('127.0.0.1',8888))

while True:

    msg = raw_input(">>>").strip()

    s1.send(msg.encode(('utf-8')))

    print "客戶端已發送數據!"

    data = s1.recv(1024)

    print data

#上面兩個代碼,可以簡單理解下socket的工作流程。


六.解決sockt 通信客戶端斷開服務端崩潰等問題的解決方法(連接循環,通信循環,以及異常捕捉)

服務端:

#!/usr/bin/python2.7

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

import socket

address_and_port = ('127.0.0.1',8888)

s1 = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)

s1.bind(address_and_port)

s1.listen(3)

while True:  #此處問連接循環,會循環等連接。

    conn,addr = s1.accept() #執行了socket的accept方法后,開始阻塞,等待客戶端的連接.

        #執行了accept方法后,會返回一個元祖,這個元祖里面包含了一個客戶端的連接對象,還有客戶端的ip地址和端口.

    while True:  #數據傳輸循環

        try:    #防止客戶端斷開導致的服務斷拋異常。

            data = conn.recv(1024) #用于接收tcp數據,后面的1024表示,recv一次最多可以接收1024字節.

            if not data:

                break

            print data

            conn.send(data.upper())

        except Exception:

            break

conn.close() #關閉與客戶端的連接

s1.close()  #關閉服務端套接字連接


客戶端:

#!/usr/bin/python2.7

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

import socket

s1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s1.connect(('127.0.0.1',8888))

while True:

    msg = raw_input(">>>").strip()

    if not msg:  #防止客戶端發送空數據

        continue

    s1.send(msg.encode(('utf-8')))

    print "客戶端已發送數據!"

    data = s1.recv(1024)

    print data

s1.close()


#以上是防止服務端崩潰的一些解決方法。






七.關于udp套接字。

服務端大概操作流程:

ss = socket()   #創建一個服務器的套接字

ss.bind()       #綁定服務器套接字

inf_loop:       #服務器無限循環

cs = ss.recvfrom()/ss.sendto() # 對話(接收與發送)

ss.close()                         # 關閉服務器套接字



客戶端大概的操作流程:

cs = socket()   # 創建客戶套接字

comm_loop:      # 通訊循環

    cs.sendto()/cs.recvfrom()   # 對話(發送/接收)

cs.close()                      # 關閉客戶套接字


下面是udp套接字的一個簡單的示例:

 示例1:

服務端:

import socket

udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

udp_server.bind(('127.0.0.1',8888))

while True:

    msg,addr = udp_server.recvfrom(1024)

    print msg ,addr

    udp_server.sendto(msg.upper(),addr)


客戶端:

import socket

udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:

    msg = raw_input(">>:").strip()

    if not msg:

        continue

    udp_client.sendto(msg.encode('utf-8'),("127.0.0.1",8888))

    back_msg,addr = udp_client.recvfrom(1024)

    print back_msg.decode('utf-8') ,addr



八.關于tcp套接字和udp套接字你需要知道的。

  1. 首先有幾點必須明確!

    1.1  所有的收發消息,都是在操作自己的tcp/udp緩沖區,發消息是將數據發送到自己的緩沖區中,收消息同樣也是從緩沖區中收取。

    1.2 tcp 使用send發消息,使用recv收消息

    1.3udp 使用sendto發消息,使用recvfrom收消息

  2. tcp與udp

    2.1 tcp是基于流的,udp是基于報的

2.2 使用send發送數據流的時候,若數據流為空,那么tcp buffer(緩沖區)也為空,操作系統不會控制tcp發包。

sendinto(bytes_data,ip_port):發送數據報,bytes_data為空,還有ip_port,所有即便是發送空的bytes_data,數據報其實也不是空的,自己這端的緩沖區收到內容,操作系統就會控制udp協議發包。

3.關于tcp的補充

tcp基于鏈接通信:

    基于鏈接,則需要listen(backlog),指定半連接池的大小

    基于鏈接,必須先運行的服務端,然后客戶端發起鏈接請求

    對于mac系統:如果一端斷開了鏈接,那另外一端的鏈接也跟著完蛋recv將不會阻塞,收到的是空(解        決方法是:服務端在收消息后加上if判斷,空消息就break掉通信循環)

    對于windows/linux系統:如果一端斷開了鏈接,那另外一端的鏈接也跟著完蛋recv將不會阻塞,收到        的是空(解決方法是:服務端通信循環內加異常處理,捕捉到異常后就break掉通訊循環)


udp通信。

無鏈接,因而無需listen(backlog),更加沒有什么連接池之說了

無鏈接,udp的sendinto不用管是否有一個正在運行的服務端,可以己端一個勁的發消息,只不過數據丟失

recvfrom收的數據小于sendinto發送的數據時,在mac和linux系統上數據直接丟失,在windows系統上發送的比接收的大直接報錯

只有sendinto發送數據沒有recvfrom收數據,數據丟失。


注意:

1.你單獨運行上面的udp的客戶端,你發現并不會報錯,相反tcp卻會報錯,因為udp協議只負責把包發出去,對方收不收,我根本不管,而tcp是基于鏈接的,必須有一個服務端先運行著,客戶端去跟服務端建立鏈接然后依托于鏈接才能傳遞消息,任何一方試圖把鏈接摧毀都會導致對方程序的崩潰。

2.上面的udp程序,你注釋任何一條客戶端的sendinto,服務端都會卡住,為什么?因為服務端有幾個recvfrom就要對應幾個sendinto,哪怕是sendinto(b'')那也要有。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女