网络编程小结

目录

软件开发架构

C/S架构

client:客户端

server:服务端

优点:软件的使用稳定,网络资源占用少

缺点:

  • 若需要使用多个软件,需要下载多个客户端
  • 服务端更新后,用户也需要跟着下载更新

B/S架构

browser:浏览器

server:服务端

优点:以浏览器充当客户端,服务端更新不需要用户更新下载

缺点: 占用网络资源大,网络不好时,体验差

互联网OSI七层协议

从下往上分为:

物理层–> 数据链路层–> 网络层–> 传输层–> 会话层–> 表示层–> 应用层

物理层

传输电信号 0100011

数据链路层

  1. 规定好电信号的分组方式

  2. 必须要由一块网卡

  3. mac地址:12位唯一的16进制数

    ​ 前6位是厂商号

    ​ 后6位是流水号

  4. 以太网协议:

    • 在同一个局域网内通信
      • 单播 1对1吼
      • 广播 多对多吼
      • 会有广播风暴, 不能对局域网通信

网络层

ip:定位局域网位置

port: 端口,唯一标识一台计算机上的一个程序

arp协议:将mac地址获取,并解析成ipi地址

传输层

TCP协议

TCP协议称之为流式协议

若想要通信,必须建立连接,并建立双向通道

三次握手,四次挥手:

  • 三次握手建立连接
    • 客户端往服务端发送建立通道
    • 服务端要确认客户端的请求,并往客户端也发送请求建立通道
    • 客户端接收到服务端建立连接的请求,并返回确认
    • 建立双向通道
  • 双向通道
    • 反馈机制
    • 客户端往服务端发送请求获取数据,服务端务必返回数据,客户端确认收到,否则会反复发送,一直到某个时间段内,会停止发送
  • 四次挥手断连接
    • 客户端往服务端发送断开连接请求,服务端返回确认收到
    • 服务端需要再次发送断开连接请求
    • 客户端返回确认收到
    • 最终确认断开来连接

UDP协议

  1. 数据不安全
  2. 不需要建立双向通道
  3. 传输速度快
  4. 不会由粘包问题
  5. 客户端发送数据,不需要服务端确认收到

应用层

ftp、http

socket套接字

socket用来写套接字客户端与服务端的模块,内部帮我们封装好了7层协议需要做的事情.

socket套接字模板

# 服务端
import socket

server = socket.socket()
server.bind(
    ('127.0.0.1', 9527)
)

server.listen(5)

while True:
    conn, addr = server.accept()
    print(addr)

    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:
                continue

            print(data.decode('utf-8'))
            conn.send(data)

        except Exception as e:
            print(e)
            break

    conn.close()
   

# 客户端
import socket

client = socket.socket()
client.connect(
    ('127.0.0.1', 9527)
)

while True:
    send_msg = input('客户端:')
    client.send(send_msg.encode('utf-8'))
    data = client.recv(1024)
    print(data.decode('utf-8'))

subprocess

用来通过代码往cmd创建一个管道,并且发送命令和接收cmd返回的结果

# 伪代码:
import subprocess
obj = subprocess.Popen(
    '命令',
    shell=True,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)
msg = obj.stdout.read() + obj.stderr.read()

粘包问题

  1. 不能确定对方发送数据的大小
  2. 在短时间内,间隔时间短,并且数据量小的情况下,默认将这些数据打包成一个多次发送的数据,然后一次性发送

struct解决粘包问题

可以将一个数据的长度打包成一个固定长度的报头.
struct.pack('模式i', '源数据长度')
data = 'gagawagwaga'
# 打包成报头
headers = struct.pack('i', len(data))

# 解包获取数据真实长度
data = struct.unpack('i', headers)[0]
# 服务端
import socket
import subprocess
import struct

server = socket.socket()
server.bind(
    ('127.0.0.1', 9527)
)

server.listen(5)

while True:
    conn, addr = server.accept()
    print(addr)

    while True:
        try:
            cmd = conn.recv(1024).decode('utf-8')
            if len(cmd) == 0:
                continue

            obj = subprocess.Popen(
                cmd,
                shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )

            res = obj.stdout.read() + obj.stderr.read()

            headers = struct.pack('i', len(res))
            conn.send(headers)
            conn.send(res)


        except Exception as e:
            print(e)
            break

    conn.close()
    
    
# 客户端
import socket
import struct


client = socket.socket()
client.connect(
    ('127.0.0.1', 9527)
)

while True:
    cmd = input('客户端输入命令:')
    client.send(cmd.encode('utf-8'))

    headers = client.recv(4)
    data_len = struct.unpack('i', headers)[0]
    data= client.recv(data_len)
    print(data.decode('gbk'))

升级版: 先将数据存放到字典中,将字典打包发送过去

字典的好处:真实数据长度;文件的描述信息;发送的数据更小

socketserver

# 服务端
import socketserver
class MyTCPServer(socketserver.BaseRequestHandler):

    def handle(self):
        print(self.client_address)

        while True:
            try:
                data = self.request.recv(1024).decode('utf-8')
                send_msg = data.upper()
                self.request.send(send_msg.encode('utf-8'))

            except Exception as e:
                print(e)
                break

if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(
        ('127.0.0.1', 9527), MyTCPServer
    )
    server.serve_forever()
    原文作者:SetCreed
    原文地址: https://www.cnblogs.com/setcreed/p/11748688.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞