網路程式設計協議(TCP和UDP協議,黏包問題)以及socketserver模組

small_caier發表於2019-01-14

網路程式設計協議

1.osi七層模型

應用層  表示層  會話層  傳輸層  網路層  資料鏈路層  物理層

2.套接字 socket 

有兩類,一種基於檔案型別,一種基於網路型別

3.Tcp和udp協議

Tcp協議:面向連線,資料可靠,傳輸效率低,面向位元組流

 建立連線與斷開連線的過程(三次握手,四次揮手)

 建立連線(三次握手):

      1.客戶端先發出訊息到服務端,請求連線

      2.服務端收到資訊後,給客戶端反饋一個資訊,等待客戶端回覆

      3.客戶端收到服務端的反饋資訊後,再像服務端發出收到訊息,連線建立

 斷開連線(四次揮手):

      1.客戶端先發出訊息到服務端,請求斷開連線

      2.服務端先傳送一個資訊,讓客戶端進行等待服務端處理通道中的資料

      3.服務端處理完通道中的資料,給客戶端傳送一個資訊,表示已經處理完資料,等待客戶端回覆

      4.客戶端收到訊息後,給服務端傳送一個回覆資訊,服務端收到後,斷開連線

tcp服務端

import socket

server = socket.socket()
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
ip_port = ("127.0.0.1",8004)
server.bind(ip_port)
server.listen(3)

while 1:
    conn,addr = server.accept()
    while 1:
        from_client_msg = conn.recv(1024)
        from_client_str = from_client_msg.decode("utf-8")
        print(from_client_str)
        to_client_msg = input("服務輸入")
        conn.send(to_client_msg.encode("utf-8"))

tcp客戶端

import socket

client = socket.socket()
ip_port = ("127.0.0.1",8004)
client.connect(ip_port)

while 1:
    to_server_msg = input("客戶輸入")
    client.send(to_server_msg.encode("utf-8"))
    from_server_msg = client.recv(1024)
    print(from_server_msg.decode("utf-8"))

Udp協議:面向無連線,資料不可靠,傳輸效率高,面向報文

upd服務端

import socket

udp_server = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ("127.0.0.1",8007)
udp_server.bind(ip_port)

from_client_msg,client_addr = udp_server.recvfrom(1024)

udp_server.sendto(b"gun",client_addr)
print(from_client_msg,client_addr)

upd客戶端

import socket

udp_client = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ("127.0.0.1",8007)

udp_client.sendto(b"hello",ip_port)

from_server_msg,server_addr = udp_client.recvfrom(1024)
print(from_server_msg,server_addr)

現在多用Tcp協議,這個更安全,但是Tcp長連線有一些問題, 會出現粘包現象, 這種現象是由緩衝區引起的

緩衝區:  將程式和網路解耦

輸入緩衝區

輸出緩衝區

Import Subprocess

    sub_obj = subprocess.Popen(

        ‘dir’,

        shell=True,

        stdout=subprocess.PIPE,  #正確結果的存放位置

        stderr=subprocess.PIPE   #錯誤結果的存放位置

 )

4.粘包

兩種粘包現象:

1 連續的小包可能會被優化演算法給組合到一起進行傳送

2 第一次如果傳送的資料大小2000B,接收端一次性接受大小為1024B,這就導致剩下的內容會被下一次recv接收到,導致結果錯亂

解決粘包的方法:

方案一:由於雙方不知道對方傳送資料的長度,導致接收的時候,可能接收不全,或者多接收另外一次傳送的資訊內容,所以在傳送真實資料之前,要先傳送資料的長度,接收端根據長度來接收後面的真實資料,但是雙方有一個互動確認的過程

方案二:

使用Struct模組,在傳送前,把檔案的大小打包,做成報頭,把報頭放在檔案真實內容之前;在接收時,對傳送過來的檔案進行解包,然後列印檔案真實內容.

打包:struct.pack(‘i’,長度)

解包:struct.unpack(‘i’,位元組)

socketserver模組實現併發

  我們之前寫的tcp協議的socket是不是一次只能和一個客戶端通訊,如果用socketserver可以實現和多個客戶端通訊。它是在socket的基礎上進行了一層封裝,也就是說底層

還是呼叫的socket。後面我們要寫的FTP作業,需要用它來實現併發,也就是同時可以和多個客戶端進行通訊,多個人可以同時進行上傳下載等。

 

服務端程式碼

import socketserver

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        while 1:
            from_client_msg = self.request.recv(1024)
            print(from_client_msg.decode("utf-8"))
            msg = input("服務")
            self.request.send(msg.encode("utf-8"))

if __name__ == `__main__`:
    ip_port = ("127.0.0.1",8001)
    server = socketserver.ThreadingTCPServer(ip_port,Myserver)
    server.serve_forever()

客戶端程式碼

import socket

client = socket.socket()
client.connect(("127.0.0.1",8001))

while 1:
    client_msg = input("客戶:")
    client.send(client_msg.encode("utf-8"))

    from_server_msg = client.recv(1024)
    print(from_server_msg.decode("utf-8"))

 

相關文章