1. 程式人生 > >python網絡編程課後練習

python網絡編程課後練習

gif pri 完整 建立連接 協議標準 AI socket 斷開連接 The

1、什麽是C/S架構?

客戶端/服務器架構。實現服務端軟件與客戶端軟件基於網絡的通信。

2、互聯網協議是什麽?分別介紹五層協議中每一層的功能?

互聯網協議是指用於互聯網通信的規範。分為:osi七層、tcp/ip五層、tcp/ip四層

物理層:基於電氣特性發送高低電壓,高電壓用1,低電壓用0

數據鏈路層:通過Ethernet協議標準將電信號進行分組

網絡層:引入一套新的地址用來區分不同的廣播域/子網,這套地址即網絡地址

傳輸層:建立端口到端口的通信,使用TCP/UDP協議

應用層:發起請求,使用http/ftp/自定義協議

3、基於tcp協議通信,為何建立鏈接需要三次握手,而斷開鏈接卻需要四次揮手

三次握手:首先客戶端給服務端發送一個syn包請求連接;服務端收到之後會對客戶端的請求作出回應,發送一個ack包給客戶端,並且同時將一個syn包發送給客戶端請求連接,即發送syn包+ack包;客戶端收到syn包+ack包之後,對服務端的請求作出確認,發送一個ack包給服務端,此時,完成三次握手,客戶端和服務端開始收發數據。

斷開連接的時候,TCP也需要互相確認才可以斷開連接,采用四次揮手斷開一個連接,客戶端如果發送完數據,就給服務端發送一個斷開連接的請求,服務端收到請求後,給客戶端發送一個確認信息,服務端接收完數據之後給客戶端發送斷開連接的請求,客戶端收到消息後給服務端發送一個確認消息,至此,連接斷開。

這樣做的原因是,兩端數據的接收並不是同時進行的,數據大小也不一樣,如果三次揮手有可能導致一端的數據接收不完整。

4、為何基於tcp協議的通信比基於udp協議的通信更可靠?

tcp協議是面向鏈接的協議,在通信過程中,雙方通過三次握手建立連接、四次揮手斷開連接,發送方給接收方發送數據,如果沒有得到接收方的回應,就會繼續給它發消息,直到接收方回應。

udp是面向數據報的協議,不需要三次握手建立連接,它不會管接收方有沒有收到數據。

5、流式協議指的是什麽協議,數據報協議指的是什麽協議?

流式協議指TCP協議,是通過三次握手建立連接再發送數據的,會存在粘包現象,當發送空消息時,對方並不會收到,不一定是一個send就要對應一個recv,傳輸效率低,網絡開銷大,可靠性高。

數據報協議是指UDP協議,是以消息為單位發送的數據的,一個sendto就對應一個recvfrom,不會存在粘包現象,即使發送空消息也能收到,傳輸效率高,網絡開銷小,可靠性低。

6、什麽是socket?簡述基於tcp協議的套接字通信流程

socket是介於應用層和傳輸層之間的一組接口。將復雜的TCP/IP協議封裝到接口裏面,使用者只需要知道怎麽用即可,不需要關心底層的實現。

基於TCP的套接字通信流程:

1)服務端:創建一個套接字對象;綁定本機地址信息;開始時監聽;接收連接;

2)客戶端:創建套接字對象;主動連接客戶端;等待對方接收

通過三次握手後建立連接,開始收發消息。

收發消息完了之後,通過四次揮手斷開連接。

7、什麽是粘包? socket 中造成粘包的原因是什麽? 哪些情況會發生粘包現象?

粘包是指兩次命令執行的結果黏在一起。粘包發生在TCP協議中。

造成粘包的原因:接收方不知道所要接收消息的大小和界限。

發生粘包的情況:1、socket緩沖區導致,socket為了提高傳輸效率,往往會將較短時間間隔內較小的數據包合並發送,這樣接收方就會收到一個粘包數據;

        2、接收方不知道該接收多大數據量,當接收方的最大接收量小於消息大小時,會發生粘包。

8、基於socket開發一個聊天程序,實現兩端互相發送和接收消息

技術分享圖片
# 服務端
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
server.bind(("127.0.0.1", 8080))
server.listen(5)
print("starting.....")
while True:
    conn, client_addr = server.accept()
    if not conn:
        break
    while True:
        msg = conn.recv(1024)
        print("from aa:", msg.decode())
        if msg.decode() == "bye":
            break
        inp = input("me:").strip()
        conn.send(inp.encode())
    conn.close()
server.close()


# 客戶端
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
client.connect(("127.0.0.1", 8080))
while True:
    msg = input("me:").strip()
    client.send(msg.encode())
    if msg == "bye":
        break
    msg1 = client.recv(1024)
    print("from xx:", msg1.decode())
    
client.close()
View Code

9、基於tcp socket,開發簡單的遠程命令執行程序,允許用戶執行命令,並返回結果

技術分享圖片
# 服務端
import socket
import subprocess
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("127.0.0.1", 8080))
s.listen(3)
while True:
    print("starting....")
    conn,addr = s.accept()
    if not conn:
        break
    while True:
        cmd = conn.recv(1024).decode()
        if not cmd:
            break
        res = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE, shell=True)
        stdout = res.stdout.read()
        stderr = res.stderr.read()
        res_len = len(stdout)+len(stderr)
        len_struct = struct.pack("i", res_len)
        conn.send(len_struct)
        conn.send(stdout)
        conn.send(stderr)
    conn.close()
s.close()


# 客戶端
import socket
import struct
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(("127.0.0.1", 8080))
while True:
    cmd = input("input command:").strip()
    c.send(cmd.encode())
    if not cmd:
        break
    header = c.recv(4)
    header_len = struct.unpack("i", header)[0]
    res = c.recv(header_len)
    print("command results:", res.decode("gbk"))
c.close()
View Code

10、基於tcp協議編寫簡單FTP程序,實現上傳、下載文件功能,並解決粘包問題

技術分享圖片
# 服務端
import socket
import os
import json
import struct


class Server:
    host = "127.0.0.1"
    port = 8080
    max_recv = 512
    serverfile = r"D:\code2\ex\刪除\文件傳輸\server\serverfile"

    def __init__(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind((self.host, self.port))
        self.sock.listen(2)

    def get(self, filename):
        """下載文件
        制作報頭,json,拿到報頭大小,壓縮報頭長度為4,發送報頭長度,發送報頭,發送文件"""
        header_dic = {"filename": filename,
                      "md5": "xxx",
                      "file_size": os.path.getsize(os.path.join(self.serverfile, filename))}
        header_bytes = json.dumps(header_dic).encode()
        header_len = len(header_bytes)
        header_struct = struct.pack("i", header_len)
        self.conn.send(header_struct)
        self.conn.send(header_bytes)
        with open(os.path.join(self.serverfile, filename), "rb") as f:
            for line in f:
                self.conn.send(line)

    def put(self, filename):
        """上傳文件
        拿到報頭長度,解壓報頭長度,接收報頭,json,拿到文件大小,接收文件"""
        header_struct = self.conn.recv(4)
        header_len = struct.unpack("i", header_struct)[0]
        header_bytes = self.conn.recv(header_len)
        header_dic = json.loads(header_bytes.decode())
        file_size = header_dic["file_size"]
        recv_size = 0
        with open(os.path.join(self.serverfile, filename), "wb") as f:
            while recv_size < file_size:
                content = self.conn.recv(self.max_recv)
                f.write(content)
                recv_size += len(content)

    def run(self):
        while True:
            print("starting....")
            self.conn,self.addr = self.sock.accept()
            if not self.conn:
                break
            while True:
                cmd = self.conn.recv(self.max_recv).decode()
                if not cmd:
                    break
                cmds = cmd.strip().split()
                if hasattr(self, cmds[0]):
                    func = getattr(self, cmds[0])
                    func(cmds[1])
            self.conn.close()
        self.sock.close()


server = Server()
if __name__ == "__main__":
    server.run()


# 客戶端
import socket
import os
import json
import struct


class Client:
    host = "127.0.0.1"
    port = 8080
    max_recv = 512
    localfile = r"D:\code2\ex\刪除\文件傳輸\client\localfile"

    def __init__(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((self.host, self.port))

    def get(self, filename):
        """下載文件
        接收報頭大小,解壓報頭大小,接收報頭,json,
        拿到文件大小,接收文件,存儲文件
        """
        header_struct = self.sock.recv(4)
        header_len = struct.unpack("i", header_struct)[0]
        header_bytes = self.sock.recv(header_len)
        header_dic = json.loads(header_bytes.decode())
        file_size = header_dic["file_size"]
        recv_size = 0
        with open(os.path.join(self.localfile, filename), "wb") as f:
            while recv_size < file_size:
                content = self.sock.recv(self.max_recv)
                f.write(content)
                recv_size += len(content)
            print("下載成功!")

    def put(self, filename):
        """上傳文件
        制作報頭,json,壓縮報頭長度,發送報頭長度,發送報頭,發送文件"""
        header_dic = {"filename": filename,
                      "md5":"xxxx",
                      "file_size":os.path.getsize(os.path.join(self.localfile, filename))}
        header_bytes = json.dumps(header_dic).encode()
        header_len = len(header_bytes)
        header_struct = struct.pack("i", header_len)
        self.sock.send(header_struct)
        self.sock.send(header_bytes)
        with open(os.path.join(self.localfile, filename), "rb") as f:
            for line in f:
                self.sock.send(line)
        print("上傳成功!")

    def run(self):
        while True:
            cmd = input("input command:").strip()
            if not cmd:
                break
            cmds = cmd.split()
            if len(cmds) == 2 and hasattr(self, cmds[0]):
                self.sock.send(cmd.encode())
                func = getattr(self, cmds[0])
                func(cmds[1])
        self.sock.close()


client = Client()
if __name__ == "__main__":
    client.run()
View Code

11、基於udp協議編寫程序,實現功能

  1)執行指定的命令,讓客戶端可以查看服務端的時間

  2)執行指定的命令,讓客戶端可以與服務的的時間同步

技術分享圖片
# 服務端
import socket
import time
import subprocess
server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server.bind(("127.0.0.1", 8080))  # 綁定IP、端口
while True:
    cmd,addr = server.recvfrom(1024)
    if not addr:
        break
    print(cmd.decode(), addr)
    if cmd.decode() == "time":  # 返回服務端時間
        time_now = time.strftime("%Y-%m-%d  %H:%M:%S", time.localtime())  # 當前日期時間
        server.sendto(time_now.encode("gbk"), addr)  # 發送
    else:  # 解析命令
        obj = subprocess.Popen(cmd.decode(), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout = obj.stdout.read()
        stderr = obj.stderr.read()
        server.sendto(stdout+stderr, addr)
server.close()


# 客戶端
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ("127.0.0.1", 8080)

while True:
    cmd = input(">>>").strip()
    if not cmd:
        break
    client.sendto(cmd.encode(), addr)  # 發送命令
    msg, addr_server = client.recvfrom(1024)  # 接收消息
    print(msg.decode("gbk"))
client.close()
View Code

python網絡編程課後練習