日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Python學(xué)習(xí)日記(三十一) 黏包問(wèn)題

系統(tǒng) 2248 0
            
              import
            
            
               subprocess

res 
            
            = subprocess.Popen(
            
              '
            
            
              dir
            
            
              '
            
            ,shell=True,stdout=subprocess.PIPE,stderr=
            
              subprocess.PIPE)

            
            
              print
            
            (
            
              '
            
            
              Stdout:
            
            
              '
            
            ,res.stdout.read().decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              ))

            
            
              print
            
            (
            
              '
            
            
              Stderr:
            
            
              '
            
            ,res.stderr.read().decode(
            
              '
            
            
              gbk
            
            
              '
            
            ))
          

PIPE把輸出的東西裝到一個(gè)'水管'里,如果在windows中的編碼格式是gbk,執(zhí)行結(jié)果:

            
              Stdout:  驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


            
            2019/09/16  13:48    
            
              
                          .

              
              2019/09/16  13:48    
              
                
                            ..

                
                2019/09/16  13:47    
                
                  
                              .idea

                  
                  2019/09/16  13:46                21
                  
                     Client1.py

                  
                  2019/09/16  13:42
                  
                                     0 Client2.py

                  
                  2019/09/16  13:48               207
                  
                     Sever1.py

                  
                  2019/09/16  01:41                70
                  
                     time_test.py

                  
                  2019/09/14  23:51    
                  
                    
                                venv
               
                    
                    4 個(gè)文件            298
                    
                       字節(jié)
               
                    
                    4 個(gè)目錄 45,863,636,992
                    
                       可用字節(jié)

Stderr: 
                    
                  
                
              
            
          

在這里也可以使用os.popen()但是它會(huì)不管正確和錯(cuò)誤的結(jié)果都放在一起,而用subprocess能夠分別拿到正確和錯(cuò)誤的信息

?

基于TCP實(shí)現(xiàn)的黏包

Sever:

            
              import
            
            
               socket
sk 
            
            =
            
               socket.socket()
sk.bind((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8092
            
              ))
sk.listen()
conn,addr 
            
            =
            
               sk.accept()

            
            
              while
            
            
               True:
    cmd 
            
            = input(
            
              '
            
            
              <<<
            
            
              '
            
            
              )
    conn.send(cmd.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    ret 
            
            = conn.recv(1024).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    
            
            
              print
            
            
              (ret)
conn.close()
sk.close()
            
          

Client:

            
              import
            
            
               socket

            
            
              import
            
            
               subprocess
sk 
            
            =
            
               socket.socket()
sk.connect((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8092
            
              ))

            
            
              while
            
            
               True:
    cmd 
            
            = sk.recv(1024).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    ret 
            
            = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=
            
              subprocess.PIPE)
    std_out 
            
            = 
            
              '
            
            
              stdout:
            
            
              '
            
             + (ret.stdout.read()).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    std_err 
            
            = 
            
              '
            
            
              stderr:
            
            
              '
            
             + (ret.stderr.read()).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    
            
            
              print
            
            
              (std_out)
    
            
            
              print
            
            
              (std_err)
    sk.send(std_out.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    sk.send(std_err.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
sk.close()
            
          

執(zhí)行結(jié)果:

Sever:

            <<<
            
              dir;ls
stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄



            
            <<<
            
              ipconfig
stderr:找不到文件


            
            <<<
          

Client:

            
              stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


stderr:找不到文件

stdout:
Windows IP 配置


以太網(wǎng)適配器 Bluetooth 網(wǎng)絡(luò)連接 
            
            2
            
              :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

以太網(wǎng)適配器 本地連接:

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

無(wú)線(xiàn)局域網(wǎng)適配器 無(wú)線(xiàn)網(wǎng)絡(luò)連接:

   連接特定的 DNS 后綴 . . . . . . . : 
   本地鏈接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:
            
            8018%14
            
              
   IPv4 地址 . . . . . . . . . . . . : 
            
            192.168.43.216
            
              
   子網(wǎng)掩碼  . . . . . . . . . . . . : 
            
            255.255.255.0
            
              
   默認(rèn)網(wǎng)關(guān). . . . . . . . . . . . . : 
            
            192.168.43.1
            
              

隧道適配器 本地連接
            
            * 3
            
              :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

stderr:
            
          

當(dāng)我們?cè)趕ever端輸入dir;ls命令時(shí),只有stdout的結(jié)果跑出來(lái),而當(dāng)我們輸入ipconfig這個(gè)命令時(shí),系統(tǒng)將上一次dir;ls未執(zhí)行完的stderr的結(jié)果給跑出來(lái)。像這樣沒(méi)有接受完全或者接受多了的就是黏包現(xiàn)象。

TCP會(huì)有黏包現(xiàn)象但是它不丟包。

?

基于UDP實(shí)現(xiàn)的黏包

Sever:

            
              import
            
            
               socket
sk 
            
            = socket.socket(type=
            
              socket.SOCK_DGRAM)
sk.bind((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8092
            
              ))
msg,addr 
            
            = sk.recvfrom(10240
            
              )


            
            
              while
            
             1
            
              :
    cmd 
            
            = input(
            
              '
            
            
              <<<
            
            
              '
            
            
              )
    
            
            
              if
            
             cmd == 
            
              '
            
            
              q
            
            
              '
            
            
              :
        
            
            
              break
            
            
              
    sk.sendto(cmd.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ),addr)
    msg,addr 
            
            = sk.recvfrom(10240
            
              )
    
            
            
              print
            
            (msg.decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              ))

sk.close()
            
          

Client:

            
              import
            
            
               socket

            
            
              import
            
            
               subprocess
sk 
            
            = socket.socket(type=
            
              socket.SOCK_DGRAM)
addr 
            
            = (
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8092
            
              )
sk.sendto(
            
            
              '
            
            
              Start
            
            
              '
            
            .encode(
            
              '
            
            
              utf-8
            
            
              '
            
            
              ),addr)

            
            
              while
            
             1
            
              :
    cmd,addr 
            
            = sk.recvfrom(10240
            
              )
    ret 
            
            = subprocess.Popen(cmd.decode(
            
              '
            
            
              gbk
            
            
              '
            
            ),shell=True,stderr=subprocess.PIPE,stdout=
            
              subprocess.PIPE)
    std_out 
            
            = 
            
              '
            
            
              Stdout:
            
            
              '
            
             + (ret.stdout.read()).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    std_err 
            
            = 
            
              '
            
            
              Stderr:
            
            
              '
            
             + (ret.stderr.read()).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    
            
            
              print
            
            
              (std_out)
    
            
            
              print
            
            
              (std_err)
    sk.sendto(std_out.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ),addr)
    sk.sendto(std_err.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ),addr)
sk.close()
            
          

執(zhí)行結(jié)果:

Sever:

            <<<
            
              dir;ls
Stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄



            
            <<<
            
              dir
Stderr:找不到文件


            
            <<<
            
              ipconfig
Stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


            
            2019/09/16  14:43    
            
              
                          .

              
              2019/09/16  14:43    
              
                
                            ..

                
                2019/09/16  14:37    
                
                  
                              .idea

                  
                  2019/09/16  14:43               553
                  
                     Client1.py

                  
                  2019/09/16  13:42
                  
                                     0 Client2.py

                  
                  2019/09/16  14:43               306
                  
                     Sever1.py

                  
                  2019/09/16  01:41                70
                  
                     time_test.py

                  
                  2019/09/14  23:51    
                  
                    
                                venv
               
                    
                    4 個(gè)文件            929
                    
                       字節(jié)
               
                    
                    4 個(gè)目錄 45,855,449,088
                    
                       可用字節(jié)


                    
                    <<<
                    
                      pwd
Stderr:

                    
                    <<<
                    
                      ip
Stdout:
Windows IP 配置


以太網(wǎng)適配器 Bluetooth 網(wǎng)絡(luò)連接 
                    
                    2
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

以太網(wǎng)適配器 本地連接:

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

無(wú)線(xiàn)局域網(wǎng)適配器 無(wú)線(xiàn)網(wǎng)絡(luò)連接:

   連接特定的 DNS 后綴 . . . . . . . : 
   本地鏈接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:
                    
                    8018%14
                    
                      
   IPv4 地址 . . . . . . . . . . . . : 
                    
                    192.168.43.216
                    
                      
   子網(wǎng)掩碼  . . . . . . . . . . . . : 
                    
                    255.255.255.0
                    
                      
   默認(rèn)網(wǎng)關(guān). . . . . . . . . . . . . : 
                    
                    192.168.43.1
                    
                      

隧道適配器 本地連接
                    
                    * 3
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 


                    
                    <<<
                  
                
              
            
          

Client:

            
              Stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


Stderr:找不到文件

Stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


            
            2019/09/16  14:43    
            
              
                          .

              
              2019/09/16  14:43    
              
                
                            ..

                
                2019/09/16  14:37    
                
                  
                              .idea

                  
                  2019/09/16  14:43               553
                  
                     Client1.py

                  
                  2019/09/16  13:42
                  
                                     0 Client2.py

                  
                  2019/09/16  14:43               306
                  
                     Sever1.py

                  
                  2019/09/16  01:41                70
                  
                     time_test.py

                  
                  2019/09/14  23:51    
                  
                    
                                venv
               
                    
                    4 個(gè)文件            929
                    
                       字節(jié)
               
                    
                    4 個(gè)目錄 45,855,449,088
                    
                       可用字節(jié)

Stderr:
Stdout:
Windows IP 配置


以太網(wǎng)適配器 Bluetooth 網(wǎng)絡(luò)連接 
                    
                    2
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

以太網(wǎng)適配器 本地連接:

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

無(wú)線(xiàn)局域網(wǎng)適配器 無(wú)線(xiàn)網(wǎng)絡(luò)連接:

   連接特定的 DNS 后綴 . . . . . . . : 
   本地鏈接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:
                    
                    8018%14
                    
                      
   IPv4 地址 . . . . . . . . . . . . : 
                    
                    192.168.43.216
                    
                      
   子網(wǎng)掩碼  . . . . . . . . . . . . : 
                    
                    255.255.255.0
                    
                      
   默認(rèn)網(wǎng)關(guān). . . . . . . . . . . . . : 
                    
                    192.168.43.1
                    
                      

隧道適配器 本地連接
                    
                    * 3
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

Stderr:
Stdout:
Stderr:
                    
                    
                      '
                    
                    
                      pwd
                    
                    
                      '
                    
                    
                       不是內(nèi)部或外部命令,也不是可運(yùn)行的程序
或批處理文件。

Stdout:
Stderr:
                    
                    
                      '
                    
                    
                      ip
                    
                    
                      '
                    
                    
                       不是內(nèi)部或外部命令,也不是可運(yùn)行的程序
或批處理文件。
                    
                  
                
              
            
          

可以看出UDP不會(huì)有黏包現(xiàn)象,會(huì)產(chǎn)生丟包現(xiàn)象,沒(méi)發(fā)完就不發(fā)了,不完整也不可靠。

?

黏包成因

TCP協(xié)議的數(shù)據(jù)傳送

拆包機(jī)制

當(dāng)發(fā)送端緩沖區(qū)的長(zhǎng)度大于網(wǎng)卡的MTU時(shí),TCP會(huì)將這次發(fā)送的數(shù)據(jù)拆成幾個(gè)數(shù)據(jù)包發(fā)送出去。MTU是Maximum Transmission Unit的縮寫(xiě),意思是網(wǎng)絡(luò)上傳送最大數(shù)據(jù)包,MTU是字節(jié)單位,大部分網(wǎng)絡(luò)設(shè)備的MTU都是1500. 如果本機(jī)的MTU比網(wǎng)關(guān)的MTU大,大的數(shù)據(jù)包就會(huì)被拆開(kāi)來(lái)傳送,這樣會(huì)產(chǎn)生很多數(shù)據(jù)包碎片,增加丟包率,降低網(wǎng)絡(luò)速度。

在正常情況下它的拆包可理解為:

Python學(xué)習(xí)日記(三十一) 黏包問(wèn)題_第1張圖片

面向流的通信特點(diǎn)和Nagle算法

TCP(transport control protocol,傳輸控制協(xié)議),是面向連接的,面向流的,提供高可靠性的服務(wù)。收發(fā)兩端(客戶(hù)端和服務(wù)端)都要有一一成對(duì)的socket,因此發(fā)送端為了將多個(gè)發(fā)往接收端的包,更有效地發(fā)往對(duì)方,使用了優(yōu)化算法(Nagle算法),將多次間隔較小且數(shù)據(jù)量小的數(shù)據(jù),合并成一個(gè)大的數(shù)據(jù)塊,然后進(jìn)行封包。這樣接收端就難于分辨出來(lái)了,必須提供科學(xué)的拆包機(jī)制。即面向流的通信是無(wú)消息保護(hù)邊界的。

對(duì)于空消息:TCP是基于數(shù)據(jù)流的,于是收發(fā)消息不能為空,這就需要在客戶(hù)端和服務(wù)端都添加空消息的處理機(jī)制,防止程序卡住,而UDP協(xié)議是基于數(shù)據(jù)報(bào)的,即便是你輸入的是空內(nèi)容(直接回車(chē)),也可以被發(fā)送,UDP協(xié)議會(huì)幫你封裝上消息然后發(fā)出去。

可靠黏包的TCP協(xié)議:TCP協(xié)議數(shù)據(jù)不會(huì)丟,沒(méi)有收完包,就會(huì)下次接收,會(huì)繼續(xù)上次繼續(xù)接受。

基于tcp協(xié)議特點(diǎn)的黏包現(xiàn)象成因

Python學(xué)習(xí)日記(三十一) 黏包問(wèn)題_第2張圖片

當(dāng)我們?cè)趕ocket服務(wù)端發(fā)送值1、2,然后根據(jù)優(yōu)化算法,它會(huì)把1先放到這個(gè)緩存當(dāng)中等一等,然后再把2一起封裝起來(lái),然后再發(fā)出去,因此我們看到的就是黏包現(xiàn)象

這種現(xiàn)象的表面現(xiàn)象是兩個(gè)send太近且發(fā)送的消息太短

發(fā)送端可以使1K1K地發(fā)送數(shù)據(jù),而接收端的應(yīng)用程序可以?xún)蒏兩K地提走數(shù)據(jù),當(dāng)然也有可能一次提走3K或6K數(shù)據(jù),或者一次只提走幾個(gè)字節(jié)的數(shù)據(jù)。也就是說(shuō),應(yīng)用程序所看到的數(shù)據(jù)是一個(gè)整體,或者說(shuō)是一個(gè)流(stream),一條消息有多少字節(jié)對(duì)應(yīng)程序是不可見(jiàn)的,因此TCP協(xié)議是面向流的協(xié)議,這也是容易出現(xiàn)黏包問(wèn)題的原因。而UDP協(xié)議是面向消息的協(xié)議,每個(gè)UDP段都是一條消息,應(yīng)用程序必須以消息單位提取數(shù)據(jù),不能一次提取任意字節(jié)的數(shù)據(jù),這一點(diǎn)和TCP是很不同的。

?

解決黏包的方法

解決方案一:

Sever:

            
              import
            
            
               socket
sk 
            
            =
            
               socket.socket()
sk.bind((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8080
            
              ))
sk.listen()
conn,addr 
            
            =
            
               sk.accept()


            
            
              while
            
            
               True:
    cmd 
            
            = input(
            
              '
            
            
              <<<
            
            
              '
            
            
              )
    
            
            
              if
            
             cmd == 
            
              '
            
            
              q
            
            
              '
            
            
              :
        conn.send(b
            
            
              '
            
            
              q
            
            
              '
            
            
              )
        
            
            
              break
            
            
              
    conn.send(cmd.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    num 
            
            = conn.recv(1024).decode(
            
              '
            
            
              utf-8
            
            
              '
            
            
              )
    conn.send(b
            
            
              '
            
            
              ok
            
            
              '
            
            
              )
    res 
            
            = conn.recv(int(num)).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    
            
            
              print
            
            
              (res)

conn.close()
sk.close()
            
          

Client:

            
              import
            
            
               socket

            
            
              import
            
            
               subprocess

sk 
            
            =
            
               socket.socket()
sk.connect((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8080
            
              ))

            
            
              while
            
            
               True:
    cmd 
            
            = sk.recv(1024).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    
            
            
              if
            
             cmd == 
            
              '
            
            
              q
            
            
              '
            
            
              :
        
            
            
              break
            
            
              
    res 
            
            = subprocess.Popen(cmd,shell=
            
              True,
                           stdout
            
            =
            
              subprocess.PIPE,
                           stderr
            
            =
            
              subprocess.PIPE)
    std_out 
            
            =
            
               res.stdout.read()
    std_err 
            
            =
            
               res.stderr.read()
    sk.send(str(len(std_out) 
            
            + len(std_err)).encode(
            
              '
            
            
              utf-8
            
            
              '
            
            
              ))
    sk.recv(
            
            1024
            
              )
    
            
            
              print
            
            (
            
              '
            
            
              Stdout:
            
            
              '
            
             + std_out.decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    
            
            
              print
            
            (
            
              '
            
            
              Stderr:
            
            
              '
            
             + std_err.decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    sk.send(std_out)
    sk.send(std_err)

sk.close()
            
          

執(zhí)行結(jié)果:

Sever:

            <<<
            
              dir
 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


            
            2019/09/17  15:33    
            
              
                          .

              
              2019/09/17  15:33    
              
                
                            ..

                
                2019/09/17  15:31    
                
                  
                              .idea

                  
                  2019/09/17  15:33               623
                  
                     Client1.py

                  
                  2019/09/16  13:42
                  
                                     0 Client2.py

                  
                  2019/09/17  15:21               389
                  
                     Sever1.py

                  
                  2019/09/16  01:41                70
                  
                     time_test.py

                  
                  2019/09/14  23:51    
                  
                    
                                venv
               
                    
                    4 個(gè)文件          1,082
                    
                       字節(jié)
               
                    
                    4 個(gè)目錄 45,031,833,600
                    
                       可用字節(jié)


                    
                    <<<
                    
                      ls

                    
                    
                      '
                    
                    
                      ls
                    
                    
                      '
                    
                    
                       不是內(nèi)部或外部命令,也不是可運(yùn)行的程序
或批處理文件。


                    
                    <<<
                    
                      ipconfig

Windows IP 配置


以太網(wǎng)適配器 Bluetooth 網(wǎng)絡(luò)連接 
                    
                    2
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

以太網(wǎng)適配器 本地連接:

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

無(wú)線(xiàn)局域網(wǎng)適配器 無(wú)線(xiàn)網(wǎng)絡(luò)連接:

   連接特定的 DNS 后綴 . . . . . . . : 
   本地鏈接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:
                    
                    8018%14
                    
                      
   IPv4 地址 . . . . . . . . . . . . : 
                    
                    192.168.43.216
                    
                      
   子網(wǎng)掩碼  . . . . . . . . . . . . : 
                    
                    255.255.255.0
                    
                      
   默認(rèn)網(wǎng)關(guān). . . . . . . . . . . . . : 
                    
                    192.168.43.1
                    
                      

隧道適配器 本地連接
                    
                    * 3
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 


                    
                    <<<
                  
                
              
            
          

Client:

            
              Stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
            
            -
            
              669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


            
            2019/09/17  15:33    
            
              
                          .

              
              2019/09/17  15:33    
              
                
                            ..

                
                2019/09/17  15:31    
                
                  
                              .idea

                  
                  2019/09/17  15:33               623
                  
                     Client1.py

                  
                  2019/09/16  13:42
                  
                                     0 Client2.py

                  
                  2019/09/17  15:21               389
                  
                     Sever1.py

                  
                  2019/09/16  01:41                70
                  
                     time_test.py

                  
                  2019/09/14  23:51    
                  
                    
                                venv
               
                    
                    4 個(gè)文件          1,082
                    
                       字節(jié)
               
                    
                    4 個(gè)目錄 45,031,833,600
                    
                       可用字節(jié)

Stderr:
Stdout:
Stderr:
                    
                    
                      '
                    
                    
                      ls
                    
                    
                      '
                    
                    
                       不是內(nèi)部或外部命令,也不是可運(yùn)行的程序
或批處理文件。

Stdout:
Windows IP 配置


以太網(wǎng)適配器 Bluetooth 網(wǎng)絡(luò)連接 
                    
                    2
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

以太網(wǎng)適配器 本地連接:

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

無(wú)線(xiàn)局域網(wǎng)適配器 無(wú)線(xiàn)網(wǎng)絡(luò)連接:

   連接特定的 DNS 后綴 . . . . . . . : 
   本地鏈接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:
                    
                    8018%14
                    
                      
   IPv4 地址 . . . . . . . . . . . . : 
                    
                    192.168.43.216
                    
                      
   子網(wǎng)掩碼  . . . . . . . . . . . . : 
                    
                    255.255.255.0
                    
                      
   默認(rèn)網(wǎng)關(guān). . . . . . . . . . . . . : 
                    
                    192.168.43.1
                    
                      

隧道適配器 本地連接
                    
                    * 3
                    
                      :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

Stderr:
                    
                  
                
              
            
          

這種寫(xiě)法的好處就是能確定Sever到底要接受多少數(shù)據(jù),不好的地方就是多了一次交互

解決方案二: 使用struct模塊

用struct模塊我們能把一個(gè)數(shù)據(jù)類(lèi)型轉(zhuǎn)換成固定長(zhǎng)度的bytes

Python學(xué)習(xí)日記(三十一) 黏包問(wèn)題_第3張圖片

這里以數(shù)字類(lèi)型舉例,'i'代表int類(lèi)型:

            
              import
            
            
               struct

            
            
              print
            
            (struct.pack(
            
              '
            
            
              i
            
            
              '
            
            ,2048),len(struct.pack(
            
              '
            
            
              i
            
            
              '
            
            ,2048)))         
            
              #
            
            
              b'\x00\x08\x00\x00'    4
            
            
              print
            
            (struct.pack(
            
              '
            
            
              i
            
            
              '
            
            ,204800),len(struct.pack(
            
              '
            
            
              i
            
            
              '
            
            ,204800)))     
            
              #
            
            
              b'\x00 \x03\x00'       4
            
            
              print
            
            (struct.pack(
            
              '
            
            
              i
            
            
              '
            
            ,2048000),len(struct.pack(
            
              '
            
            
              i
            
            
              '
            
            ,2048000)))   
            
              #
            
            
              b'\x00@\x1f\x00'       4
            
          

當(dāng)后面的數(shù)值戳過(guò)一定范圍的時(shí)候程序就會(huì)報(bào)錯(cuò)

Sever:

            
              import
            
            
               socket

            
            
              import
            
            
               struct
sk 
            
            =
            
               socket.socket()
sk.bind((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8080
            
              ))
sk.listen()
conn,addr 
            
            =
            
               sk.accept()


            
            
              while
            
            
               True:
    cmd 
            
            = input(
            
              '
            
            
              <<<
            
            
              '
            
            
              )
    
            
            
              if
            
             cmd == 
            
              '
            
            
              q
            
            
              '
            
            
              :
        conn.send(b
            
            
              '
            
            
              q
            
            
              '
            
            
              )
        
            
            
              break
            
            
              
    conn.send(cmd.encode(
            
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    num 
            
            = conn.recv(4
            
              )
    num 
            
            = struct.unpack(
            
              '
            
            
              i
            
            
              '
            
            
              ,num)[0]
    res 
            
            = conn.recv(int(num)).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    
            
            
              print
            
            
              (res)

conn.close()
sk.close()
            
          

Client:

            
              import
            
            
               socket

            
            
              import
            
            
               subprocess

            
            
              import
            
            
               struct

sk 
            
            =
            
               socket.socket()
sk.connect((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8080
            
              ))

            
            
              while
            
            
               True:
    cmd 
            
            = sk.recv(1024).decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              )
    
            
            
              if
            
             cmd == 
            
              '
            
            
              q
            
            
              '
            
            
              :
        
            
            
              break
            
            
              
    res 
            
            = subprocess.Popen(cmd,shell=
            
              True,
                           stdout
            
            =
            
              subprocess.PIPE,
                           stderr
            
            =
            
              subprocess.PIPE)
    std_out 
            
            =
            
               res.stdout.read()
    std_err 
            
            =
            
               res.stderr.read()
    len_num 
            
            = len(std_out) +
            
               len(std_err)
    num_by 
            
            = struct.pack(
            
              '
            
            
              i
            
            
              '
            
            
              ,len_num)
    
            
            
              print
            
            (
            
              '
            
            
              Stdout:
            
            
              '
            
             + std_out.decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    
            
            
              print
            
            (
            
              '
            
            
              Stderr:
            
            
              '
            
             + std_err.decode(
            
              '
            
            
              gbk
            
            
              '
            
            
              ))
    sk.send(num_by)
    sk.send(std_out)
    sk.send(std_err)

sk.close()
            
          

執(zhí)行結(jié)果:

              <<<
              
                dir
 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
              
              -
              
                669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


              
              2019/09/17  16:25    
              
                
                            .

                
                2019/09/17  16:25    
                
                  
                              ..

                  
                  2019/09/17  16:23    
                  
                    
                                .idea

                    
                    2019/09/17  16:25               659
                    
                       Client1.py

                    
                    2019/09/16  13:42
                    
                                       0 Client2.py

                    
                    2019/09/17  16:22               400
                    
                       Sever1.py

                    
                    2019/09/17  16:08               288
                    
                       time_test.py

                    
                    2019/09/14  23:51    
                    
                      
                                  venv
               
                      
                      4 個(gè)文件          1,347
                      
                         字節(jié)
               
                      
                      4 個(gè)目錄 45,025,951,744
                      
                         可用字節(jié)


                      
                      <<<
                      
                        configip

                      
                      
                        '
                      
                      
                        configip
                      
                      
                        '
                      
                      
                         不是內(nèi)部或外部命令,也不是可運(yùn)行的程序
或批處理文件。


                      
                      <<<
                      
                        ipconfig

Windows IP 配置


以太網(wǎng)適配器 Bluetooth 網(wǎng)絡(luò)連接 
                      
                      2
                      
                        :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

以太網(wǎng)適配器 本地連接:

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

無(wú)線(xiàn)局域網(wǎng)適配器 無(wú)線(xiàn)網(wǎng)絡(luò)連接:

   連接特定的 DNS 后綴 . . . . . . . : 
   本地鏈接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:
                      
                      8018%14
                      
                        
   IPv4 地址 . . . . . . . . . . . . : 
                      
                      192.168.43.216
                      
                        
   子網(wǎng)掩碼  . . . . . . . . . . . . : 
                      
                      255.255.255.0
                      
                        
   默認(rèn)網(wǎng)關(guān). . . . . . . . . . . . . : 
                      
                      192.168.43.1
                      
                        

隧道適配器 本地連接
                      
                      * 3
                      
                        :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 


                      
                      <<<
                    
                  
                
              
            
Sever執(zhí)行結(jié)果
              
                Stdout: 驅(qū)動(dòng)器 C 中的卷是 系統(tǒng)
 卷的序列號(hào)是 85C0
              
              -
              
                669A

 C:\Users\Administrator\PycharmProjects\Internet_program 的目錄


              
              2019/09/17  16:25    
              
                
                            .

                
                2019/09/17  16:25    
                
                  
                              ..

                  
                  2019/09/17  16:23    
                  
                    
                                .idea

                    
                    2019/09/17  16:25               659
                    
                       Client1.py

                    
                    2019/09/16  13:42
                    
                                       0 Client2.py

                    
                    2019/09/17  16:22               400
                    
                       Sever1.py

                    
                    2019/09/17  16:08               288
                    
                       time_test.py

                    
                    2019/09/14  23:51    
                    
                      
                                  venv
               
                      
                      4 個(gè)文件          1,347
                      
                         字節(jié)
               
                      
                      4 個(gè)目錄 45,025,951,744
                      
                         可用字節(jié)

Stderr:
Stdout:
Stderr:
                      
                      
                        '
                      
                      
                        configip
                      
                      
                        '
                      
                      
                         不是內(nèi)部或外部命令,也不是可運(yùn)行的程序
或批處理文件。

Stdout:
Windows IP 配置


以太網(wǎng)適配器 Bluetooth 網(wǎng)絡(luò)連接 
                      
                      2
                      
                        :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

以太網(wǎng)適配器 本地連接:

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

無(wú)線(xiàn)局域網(wǎng)適配器 無(wú)線(xiàn)網(wǎng)絡(luò)連接:

   連接特定的 DNS 后綴 . . . . . . . : 
   本地鏈接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:
                      
                      8018%14
                      
                        
   IPv4 地址 . . . . . . . . . . . . : 
                      
                      192.168.43.216
                      
                        
   子網(wǎng)掩碼  . . . . . . . . . . . . : 
                      
                      255.255.255.0
                      
                        
   默認(rèn)網(wǎng)關(guān). . . . . . . . . . . . . : 
                      
                      192.168.43.1
                      
                        

隧道適配器 本地連接
                      
                      * 3
                      
                        :

   媒體狀態(tài)  . . . . . . . . . . . . : 媒體已斷開(kāi)
   連接特定的 DNS 后綴 . . . . . . . : 

Stderr:
                      
                    
                  
                
              
            
Client執(zhí)行結(jié)果

實(shí)現(xiàn)一個(gè)大文件的傳輸和下載

當(dāng)我們?cè)诰W(wǎng)絡(luò)上傳輸所有數(shù)據(jù)時(shí),這些數(shù)據(jù)都叫數(shù)據(jù)包,數(shù)據(jù)包里的所有數(shù)據(jù)都叫報(bào)文,報(bào)文里不止有你的數(shù)據(jù)還有IP地址、MAC地址、端口號(hào)等,所有的報(bào)文都有報(bào)頭,這是由協(xié)議規(guī)定的。所有在網(wǎng)絡(luò)上傳播數(shù)據(jù)包的協(xié)議里都有一個(gè)報(bào)頭。什么時(shí)候需要自己定制報(bào)文?比如說(shuō)復(fù)雜的應(yīng)用上就會(huì)應(yīng)用到、傳輸文件的時(shí)候(文件名、文件大小、文件類(lèi)型、存儲(chǔ)路徑等)...

其實(shí)在網(wǎng)絡(luò)傳輸?shù)倪^(guò)程當(dāng)中處處有協(xié)議,協(xié)議就是一堆報(bào)頭和報(bào)文(都由字節(jié)組成)。

Sever:

            
              import
            
            
               socket

            
            
              import
            
            
               struct

            
            
              import
            
            
               json
buffer 
            
            = 1024
            
              
sk 
            
            =
            
               socket.socket()
sk.bind((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8080
            
              ))
sk.listen()

conn,addr 
            
            =
            
               sk.accept()

head_len 
            
            = conn.recv(4
            
              )
struct.unpack(
            
            
              '
            
            
              i
            
            
              '
            
            
              ,head_len)[0]
json_head 
            
            = conn.recv(head_len).decode(
            
              '
            
            
              utf-8
            
            
              '
            
            
              )
head 
            
            =
            
               json.loads(json_head)
file_size 
            
            = head[
            
              '
            
            
              fileSize
            
            
              '
            
            
              ]

with open(r
            
            
              '
            
            
              dir\%s
            
            
              '
            
            %head[
            
              '
            
            
              fileName
            
            
              '
            
            ],
            
              '
            
            
              wb
            
            
              '
            
            
              ) as f:
    
            
            
              while
            
            
               file_size:
        
            
            
              if
            
             file_size >=
            
               buffer:
            content 
            
            =
            
               conn.recv(buffer)
            f.write(content)
            file_size 
            
            -=
            
               buffer
        
            
            
              else
            
            
              :
            content 
            
            =
            
               conn.recv(buffer)
            f.write(content)
            
            
            
              break
            
            
              
conn.close()
sk.close()
            
          

Client:

            
              import
            
            
               socket

            
            
              import
            
            
               struct

            
            
              import
            
            
               os

            
            
              import
            
            
               json

sk 
            
            =
            
               socket.socket()
sk.connect((
            
            
              '
            
            
              127.0.0.1
            
            
              '
            
            ,8080
            
              ))
buffer 
            
            = 1024
            
              
head 
            
            = {
            
              '
            
            
              filePath
            
            
              '
            
             : r
            
              '
            
            
              C:\Users\Administrator\Desktop\專(zhuān)題\海報(bào)資料夾\專(zhuān)題海報(bào)
            
            
              '
            
            
              ,
        
            
            
              '
            
            
              fileName
            
            
              '
            
             : r
            
              '
            
            
              專(zhuān)題海報(bào)
            
            
              '
            
            
              ,
        
            
            
              '
            
            
              fileSize
            
            
              '
            
            
               : None}
file_path 
            
            = os.path.join(head[
            
              '
            
            
              filePath
            
            
              '
            
            ],head[
            
              '
            
            
              fileName
            
            
              '
            
            
              ])
file_size 
            
            =
            
               os.path.getsize(file_path)

head[
            
            
              '
            
            
              fileSize
            
            
              '
            
            ] =
            
               file_size
json_head 
            
            = json.dumps(head)                            
            
              #
            
            
              字典轉(zhuǎn)成字典
            
            
bytes_head = json_head.encode(
            
              '
            
            
              utf-8
            
            
              '
            
            )                  
            
              #
            
            
              字符串轉(zhuǎn)bytes
            
            
              
head_len 
            
            = len(bytes_head)                              
            
              #
            
            
              報(bào)頭的長(zhǎng)度
            
            
pack_len = struct.pack(
            
              '
            
            
              i
            
            
              '
            
            
              ,head_len)

sk.send(pack_len)                                       
            
            
              #
            
            
              先發(fā)報(bào)頭的長(zhǎng)度
            
            
sk.send(bytes_head)                                     
            
              #
            
            
              再發(fā)bytes類(lèi)型的報(bào)頭
            
            
with open(r
            
              '
            
            
              dir\%s
            
            
              '
            
            %file_path,
            
              '
            
            
              rb
            
            
              '
            
            
              ) as f:
        
            
            
              while
            
            
               file_size:
                
            
            
              if
            
             file_size >=
            
               buffer:
                        content 
            
            = f.read(buffer)  
            
              #
            
            
               每次文件讀出的內(nèi)容
            
            
                                      sk.send(content)
                        file_size 
            
            -=
            
               buffer
                
            
            
              else
            
            
              :
                        content 
            
            =
            
               f.read(file_size)
                        sk.send(content)
                        
            
            
              break
            
            
              
sk.close()
            
          

更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 长海县| 刚察县| 壤塘县| 乡宁县| 新闻| 张家口市| 北辰区| 元朗区| 砚山县| 微山县| 万安县| 焉耆| 万全县| 武威市| 江山市| 台北市| 太谷县| 威宁| 长葛市| 宜君县| 敦化市| 玛纳斯县| 宿州市| 油尖旺区| 青龙| 吕梁市| 昂仁县| 通辽市| 临泽县| 沙坪坝区| 昭通市| 始兴县| 绍兴县| 巴林左旗| 襄樊市| 甘孜| 龙南县| 尼勒克县| 绥芬河市| 屯留县| 普宁市|