欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

网络编程小结

程序员文章站 2022-08-02 08:02:42
[TOC] 软件开发架构 C/S架构 client:客户端 server:服务端 优点:软件的使用稳定,网络资源占用少 缺点: 若需要使用多个软件,需要下载多个客户端 服务端更新后,用户也需要跟着下载更新 B/S架构 browser:浏览器 server:服务端 优点:以浏览器充当客户端,服务端更新 ......

软件开发架构

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()