zoukankan      html  css  js  c++  java
  • 网络编程——总结

    网络编程总复习

    1.网络编程

    • 软件开发架构

      • c/s架构:

        ​ c: 客户端

        ​ s: 服务端

      • b/s架构

        ​ b: 浏览器

        ​ s: 服务器

    服务端:24 H 不间断提供服务

    客户端: 需要时找服务器提供服务

    网络编程》》》》》》学习cs架构软件

    并发编程:前端,数据库,框架》》》》》》开发bs架构软件

    实现网络通信的前提:物理连接介质

    统一的标准:协议

    2、OSI 七层协议

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

    • 物理链路层:

    • 实现计算机之间物理连接,传输的都是010101010的二进制

    • 基于电信号工作原理:只有高低电平

    • 数据链路层(以太网协议):通讯方式基本靠吼

      • 规定了二进制的数据分组方式

      • 规定每个接入互联网的设备都必须有一块网卡

        • 每块网卡都必须有世界唯一的mac地址(通常由12位16进制数表示(前六位是厂商编号,后六位是流水线号))
    • 网络层(IP协议):

      • 规定了每个计算机都必须有IP(ipv4和ipv6)
      • ip地址能够唯一标识互联网中独一无二的一台机器
    • 传输层(端口协议):TCP,UDP基于端口工作的协议

      • 计算机应用程序与应用程序之间的通讯

      • 端口(port):唯一标识一台计算机上的某一个基于网络的通讯的协议

        '''
        	端口范围:0~65535(动态分配)
        		注意:0~1024通常是归操作系统分配的端口号
        		通常情况下,我们写的软件端口号建议起在8000之后
        		flask框架默认端口5000
        		django框架默认端口8000
        		mysql数据库默认端口3306
        		redis数据库默认端口6379
        '''
        	
        	
        
    TCP(流式协议,可靠协议)
    	三次握手四次挥手
    

    UDP协议(数据报协议)
    	无需建立双向连接,并且传输数据不可靠,可能会出现丢包的情况
    	通信速度比较快,但是发送的数据不会在内存中保留!
    qq用的就是udp协议
    

    3、socket层

    • 什么是socket层?

      • socket 是 应用层和tcp/ip协议之间通讯的抽象层,是一组接口

    • socket工作流程

      # 服务端:
      '''
      服务器端先初始化socket,然后与端口绑定(bind),对端口进行监听(listen)
      调用(accept)阻塞,等待客户端连接。
      '''
      # 客户端:
      '''
      客户端初始化socket,然后连接服务器(connect)
      '''
      # 通讯连接
      '''
      连接成功,客户端与服务器端的连接就建立好了,客户端发送数据请求,服务端接收并且处理请求,然后把回应数据发送给客户端回应
      客户端读取数据,关闭连接,完成一次交互
      '''
      

    • 服务端套接字函数
    s.bind()    绑定(主机,端口号)到套接字
    s.listen()  开始TCP监听
    s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来
    
    • 客户端套接字函数
    s.connect()     主动初始化TCP服务器连接
    s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
    
    • 公共端套接字函数
    s.recv()            接收TCP数据
    s.send()            发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
    s.sendall()         发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
    s.recvfrom()        接收UDP数据
    s.sendto()          发送UDP数据
    s.getpeername()     连接到当前套接字的远端的地址
    s.getsockname()     当前套接字的地址
    s.getsockopt()      返回指定套接字的参数
    s.setsockopt()      设置指定套接字的参数
    s.close()           关闭套接字
    
    • socket (TCP)模块程序

    # 服务端
    import socket
    
    # 指定端口和每次数据长度
    IP_PORT = ('127.0.0.1', 8080)  # 电话卡
    BUFSIZE = 1024
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买电话
    
    server.bind(IP_PORT)  # 插电话卡
    server.listen(5)  # 待机
    
    while True:  # 接收连接循环,可以不停的接电话
        conn, addr = server.accept()  # 接电话 阻塞:等待客户端连接
    
        while True:  # 新增接收连接的循环,可以不断的通讯
            try:
                msg = conn.recv(BUFSIZE)  # 听电话
                if len(msg) == 0: break  # 防止如果正在连接次client断开,recv发生死循环
                print(msg)
    
                conn.send(msg.upper()) # 发消息
    
            except ConnectionResetError:
                break
        conn.close()
    server.close()
    
    
    # 客户端
    import socket
    
    IP_PORT = ('127.0.0.1', 8080)  # 电话卡
    BUFSIZE = 1024
    
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买手机
    
    client.connect(IP_PORT) # 插卡
    
    while True: # 循环连接
    
        msg = input('请输入你:').strip()
        if len(msg) == 0: continue
        client.send(msg.encode('utf-8')) # 发送给服务端
    
        serverback=client.recv(BUFSIZE) # 接收服务端反馈
        print(serverback.decode('utf-8'))
    
    s.close()
    
    
    

    • 粘包问题

      注:只有tcp才有粘包问题,因为TCP协议是流式协议

      • 什么是粘包:
        • 所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
      • 粘包发生的情况:
        • 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
        • 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
    • 粘包的解决方法

      • 发送数据直接先告诉对方数据大小

      • 利用struct模块制定消息传递协议

    • 利用struct 解决方法

    • 发送时

      • 先制作报头字典,字典里包括:真实数据的信息,然后利用json序列化,
      • 利用struct进行打包成4个字节的报头
      • 先发送报头长度
      • 编码报头内容发送
      • 最后发送真实内容
    • 接收时

      • 先接收报头长度,用struct取出来
      • 根据报头长度接收报头内容,然后编码,反序列化
      • 从反序列化的结果中抽取带去的数据详细信息,然后去真实的数据内容
    • 案例:利用socket发送大文件

    # 客户端
    import socket
    import struct
    import json
    import os
    
    IP_PORT = ('127.0.0.1',8080)
    client = socket.socket()
    client.connect(IP_PORT)
    
    file_path = r'F:python_s7网络编程复习a'
    file_size = os.path.getsize(file_path)
    
    dic = {
        'file_name': 'b',
        'file_siz': file_size,
    }
    # json序列化
    header_json = json.dumps(dic)
    header_bytes = header_json.encode('utf-8')
    
    # 制作字典报头
    header = struct.pack('i',len(header_bytes))
    
    # 发送报头
    client.send(header)
    
    # 发送字典数据
    client.send(header_bytes)
    
    # 发送真实内容
    with open(file_path,'rb')as f:
        for line in f:
            client.send(line)
    
    
    # 服务端
    import socket
    import json
    import struct
    
    
    IP_PORT = ('127.0.0.1',8080)
    server = socket.socket()
    server.bind(IP_PORT)
    server.listen(5)
    
    while True:
        conn,addr = server.accept()
        while True:
            try:
                header = conn.recv(4)
                if len(header)==0:break
                dic_len = struct.unpack('i',header)[0]
                dic = json.loads(conn.recv(dic_len).decode('utf-8'))
    
                file_name = dic['file_name']
                file_size = dic['file_size']
                recv_size =  0
                with open(file_name,'wb') as f :
                    while recv_size<file_size:
                        data = conn.recv(1024)
                        f.write(data)
                        recv_size += len(data)
    
            except ConnectionResetError:
                break
    
    
    • socket(UDP)协议

    """
    1.udp协议客户端允许发空
    2.udp协议不会粘包
    3.udp协议服务端不存在的情况下,客户端照样不会报错
    4.udp协议支持并发
    
    UDP叫数据报协议,意味着发消息都带有数据报头
    udp的server不需要就行监听也不需要建立连接
    在启动服务之后只能被动的等待客户端发送消息过来,客户端发送消息的时候,要带上服务端的地址
    服务端在回复消息的时候,也需要带上客户端的地址
    """
    
    # 服务端
    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    
    msg, addr = server.recvfrom(1024)
    print(msg.decode('utf-8'))
    server.sendto(b'hello', addr)
    
    server.close()
    
    #客户端
    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8080)
    
    client.sendto(b'hello server baby!', server_addr)
    msg, addr = client.recvfrom(1024)
    print(msg, addr)
    

    4、socketsever 实现并发

    # TCP socketserver使用
    import socketserver
    
    class MyTcpSever(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                try:
                    # self.request 相当于conn对象
                    data = self.request.recv(1204)
                    if len(data) == 0: break
                    print(data)
                    self.request.send(data.upper())
    
                except ConnectionResetError:
                    break
    
    if __name__ == '__main__':
        sever = socketserver.ThreadingTCPServer(('127.0.0.1',8081),MyTcpSever)
        sever.serve_forever()
    # Tcp客户端
    import socket
    
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    
    while True:
        client.send(b'hello')
        data = client.recv(1024)
        print(data)
    
    
    
    # UDP socketserver使用
    import socketserver
    
    
    class MyUdpServer(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                data, sock = self.request
                print(data)
                sock.sendto(data.upper(), self.client_address)
    
    
    if __name__ == '__main__':
        server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyUdpServer)
        server.serve_forever()
        
    # UDP 客户端
    import socket
    import time
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1',8080)
    
    while True:
        client.sendto(b'hello',server_addr)
        data,addr = client.recvfrom(1024)
        print(data,addr)
        time.sleep(1)
    
        
    
  • 相关阅读:
    DEDECMS5.5/5.6/5.7列表页调用TAG标签(热门标签)的两种方法
    DEDE列表页和内容页调用顶级栏目ID的方法
    解决dede图集上传图片时跳出302错误
    DEDE用{dede:sql}标签取出当前文档的附加表中的内容
    DEDE模板中如何运行php脚本和php变量的使用
    织梦DEDECMS {dede:arclist},{dede:list}获取附加表字段内容
    把DEDE的在线文本编辑器换成Kindeditor不显示问题
    ExtJS:文件上传实例
    ExtJS:GridPanel之renderer:function()和itemdblclick : function()方法参数详解
    ExtJS:菜单ComboBox及级联菜单应用
  • 原文地址:https://www.cnblogs.com/king-home/p/10885841.html
Copyright © 2011-2022 走看看