网络编程基础

网络编程基础

一、架构分类:

  • C/S架构:client客户端和server服务端
  • B/S架构:browser浏览器和server服务端

B/S架构隶属于C/S架构,C/S架构的优势是可以充分的调度PC机的性能,但是B/S架构的优势是统一了接口

二、网络通信基础

  • 局域网与交换机的通信原理
    交换机

  • ip地址:用来标记电脑用于识别,并且不允许重复。在网络通信中可以在传递信息的时候通过ip地址识别出接收方。

    • mac和linux通过命令行终端输入ifconfig来查看ip地址,Windows在命令行中通过ipconfig来查看
    • linux中命令行关闭网卡:sudo ifconfig 网卡名 down, 开启网卡:sudo ifconfig 网卡名 up
    • ip版本:
      • ip v1-v3:实验版本
      • ip v4:地址由四组数组成,每组数由逗号隔开,每组数中的最大值是255,最小值为0。ip地址组合的后最大ip地址数量:256256256*256,已经分配完,但是网络需求越来越大。
      • ip v5:实验版本
      • ip v6:为了解决ip地址不够的问题,但是ip v6普及率还不够。
    • ip的组成:192.168.33.xx,由网络号和主机号两部分组成。
      • 版本一:前三组标记网络号,后边一组是主机号,网络号相同的情况下主机号绝对不能一样。每一组号码从0-255,理论上这个网络好可以容纳256个主机,但是需要注意的是主机号不能有两个数字不能用:0和255。
      • 版本二:前两组为网络号,后两组为主机号,理论上的主机号数量为:256*256=65536
      • 版本三:第一组为网络号,后三组为主机号,理论上的主机号数量为:256256256=16777216

      具体使用哪种版本根据具体的人数和需求来定。回环地址:127.0.0.1,表示的是本机,不能连接到其他人

  • 端口

    • 端口号是异种骨特殊的网络通道,端口号只有整数,从0到65535

    • 为什么要有端口号:
      在网络通信的过程中,通过ip地址来确定信息发送给/接收自拿一台电脑,在接收到信息后电脑需要确定信息应该转给哪个程序来处理,此时ip地址已经不起作用,需要定义端口号来确定

    • 端口分类:

      • 知名端口:众所周知的端口号,范围从0-1023,80端口分配给HTTP服务,21端口分配给FTP服务。
      • 动态端口:可以随便使用的端口号,范围从1024-65535
  • 网络通信发送消息必须具备的具体内容:

    • dest ip:目标ip,用于识别接收信息的电脑
    • src ip:源ip,发送信息的电脑ip,即本机,用于目标ip回传信息时识别本机
    • dest port: 目标端口号,用于识别哪一个软件来接收并处理信息
    • src port: 源端口号,用于识别本机哪一个软件来接收并处理回传的信息
    • content: 网络通信中传送信息的内容

三、socket

  • 定义:socket(简称:套接字)是进程之间通信的一种方式,也可以理解为插排。它与其他进程间通信的一个区别是:它能实现不同主机间进程的通信,网络上各种各样的软件基本上都是基于socket来实现通信的。

  • 创建套接字的基本格式:

    • 导入socket:import socket
    • 创建套接字:s = socket.socket(AddressFamily, Type)
      • AddressFamily
        • 用于internet间进程的通信,ipv4必须写成socket.AF_INET
        • 用于同一台机器间进程的通信, 必须写成AF_UNIX
        • 实际工作中常用AF_INET
      • Type:套接字类型,可以使用socket.SOCK_STREAM(流式套接字,主要用于TCP通信)或者socket.SOCK_DGRAM(数据报套接字,主要用于UDP协议)。注意大小写。
    • 关闭socket对象:s.close()
  • 服务端与客户端实现通信:

    • server:
      • 创建套接字sk
      • sk.bind(('ip地址', 端口号))
      • 设置监听:conn, addr = sk.accept()
      • 接收客户端消息msg_r = conn.recv(接收的字节数).decode('utf-8'),并打印
      • 向客户端发送消息:msg_s = types(input('>>>'.encode('utf-8'))),conn.send(msg_s)
      • 断开连接:conn.close()
      • 关闭套接字:sk.close()
    import socket
    import logging
    logging.basicConfig(
        level = logging.DEBUG,
        format = '%(asctime)s %(filename)s [line: %(lineno)d] %(message)s %(process)d',
        datefmt = '%a, %b, %d, %Y %H:%M:%S',
        filename = '../网络基础/server1.log'
    )
    
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.bind(('172.16.12.157', 8003))
    sk.listen()
    conn, addr = sk.accept()
    while 1:
        msg_r = conn.recv(1024).decode('utf-8')
        if msg_r:
            logging.debug('服务端接收一条消息')
            if msg_r == 'q':
                break
            else:
                print(msg_r)
    
        msg_s = bytes(input('>>>>').encode('utf-8'))
        conn.send(msg_s)
        logging.debug('服务端发送一条消息')
    
    conn.close()
    sk.close()
    
    • client:
      • 创建套接字
      • 建立连接:sk.connect(('ip地址', 端口号))
      • 向服务端发送消息:msg_s = types(input('>>>'.encode('utf-8'))),sk.send(msg_s)
      • 接收服务端消息msg_r = sk.recv(接收的字节数).decode('utf-8'),并打印
      • 关闭套接字:sk.close()
    import socket
    import logging
    
    '''创建日志'''
    logger = logging.getLogger()
    # 创建日志对象
    logger.setLevel(logging.DEBUG)
    fh = logging.FileHandler('client1.log', encoding='utf-8')
    sh = logging.StreamHandler()
    # 创建文件和屏幕句柄
    format = logging.Formatter('%(asctime)s %(filename)s [line: %(lineno)d %(message)s %(process)d')
    sh.setFormatter(format)
    fh.setFormatter(format)
    logger.addHandler(sh)
    logger.addHandler(fh)
    
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.connect(('172.16.12.157', 8003))
    
    while 1:
        try:
            msg_s = input('>>>>')
            if msg_s == 'q':
                msg_s = bytes(msg_s.encode('utf-8'))
                sk.send(msg_s)
                break
            else:
                msg_s = bytes(msg_s.encode('utf-8'))
            sk.send(msg_s)
        except ValueError:
            print('输入格式不正确,请重新输入')
            msg_s = input('>>>>')
        finally:
            logging.debug('客户端发送一条消息')
        msg_r = sk.recv(1024).decode('utf-8')
        print(msg_r)
        if msg_r:
            logging.debug('客户端接收一条消息')
    
    sk.close()
    
    

注意:服务端发送和接收消息都用的是conn,客户端使用的是套接字sk

四、TCP和UDP协议:

  • TCP协议:

    • 特征及使用的场景:
      • 需要先建立连接,然后才能通信
      • 占用连接,可靠性高(消息不会丢失),实时性高,速度慢
      • 使用的场景:语音/视频聊天、线下缓存高清视频、qq远程控制、发邮件等
    • 建立连接中期间的三次握手:
      • 过程:
        • 客户端向服务端发送建立连接的请求SYN
        • 服务端发送同意ACK,此时客户端向服务端通信的连接已经建立
        • 服务端向客户端发送建立连接的请求SYN
        • 客户端发送同意ACK

        由于服务端向客户端发送的ACK及SYN可以同时发送,所以合并为一条,被成为三次握手。

    三次握手

    • 结束连接时的四次挥手:
      • 过程:
        • 主动端发送断开连接的FIN请求
        • 被动端收到请求后发送同意ACK
        • 被动端向主动端发送断开连接的FIN请求
        • 主动端收到后回复同意ACK,断开连接

    四次挥手

为什么建立连接是三次握手,而断开连接却是四次挥手,为什么不能合并为三次挥手:
因为在三次握手的时候还没有传输数据,可以合并,而四次挥手的时候可能还正在传输数据,如果四次挥手合并为三次会造成数据无法发送或者丢失。

  • UDP协议
    特征及使用的场景:
    • 不需要建立连接,就可以进行通信
    • 不占用连接、传输不可靠(因为网络不稳定的原因可能会造成数据的丢失,丢包)、传输的速度很快
    • 使用的场景:在线播放视频、qq/微信发送消息等。
posted @ 2020-02-17 19:10  大道至诚  阅读(120)  评论(0编辑  收藏  举报