zoukankan      html  css  js  c++  java
  • python网络编程

    网络编程

    part1:

    网络编程基础

    • 不变的:mac地址能够唯一标识你这台机器的

    • 变化的:ip地址能够更好的更方便的找到你的机器

    • 局域网:

      • 网段交换机不能理解ip地址,只能理解mac地址
    • 局域网和局域网之间通信了:

      • 网关路由器可以理解ip地址
    • ip地址:

      • *ipv4:四位点分十进制
      • *公网地址:需要我们自己申请购买的地址
      • *内网地址:保留字段(不在这个范围内的都是公网ip)
      • *特殊的ip地址
        • 127.0.0.1本地回环地址(表示我自己)测试的时候用的(过网卡不过交换机)
    • *查看自己的ip地址ipconfig(window10)/ifconfig(mac/linux)

    • *子网掩码也是一个ip地址用来判断两台机器在不在一个局域网内

    • IPV6(一般小公司ipv4大公司ipv6)

    • ip/mac确认机器的

    • 端口确认机器上的具体应用程序的

    • 概念的整理

      • 局域网的概念
        • 交换机
          • 在同一个局域网内的机器由交换机负责通信
          • 交换机只认识mac地址
          • 可以完成广播 组播 单播
        • 单播--mac地址(在网卡上)
      • 局域网之间通信
        • 路由器
          • 提供网关ip,同一个局域网的所有机器共享一个网关
          • 我们不能访问除了本局域网之外的其他内网的IP地址
        • 子网掩码
          • 用来判断两台机器是不是在一个网段内
      • ip地址:ipv4协议ipv6协议
      • mac地址:arp协议(通过ip找mac)
    • 端口port:用来确认一台机器上的具体应用

    osi五(七)层协议

    osi五层协议

    • 应用层 python代码
    • 传输层 port tcp udp 四层路由器 四层交换机
    • 网络层 ipv4 ipv6 路由器三层交换机
    • 数据链路层 mac arp协议 网卡 二层交换机(单播,广播,组播arp协议用到前两种)
    • 物理层

    tcp和udp

    • tcp(语音聊天/视频聊天)-线下缓存高强电影qq远程控制发邮件
      • 需要先建立连接然后才能通信的

      • 占用连接可靠(消息不会丢失)实时性高慢

      • 建立连接-三次握手(握手有客户段发起请求)

      • 断开连接-四次挥手

      • 什么是三次握手?什么是四次挥手?为什么握手是三次挥手是四次?这个过程都传递了哪些信号

      • 因为可能我有些话可能没跟他说完/他有些话可能没跟我说完

    	tcp协议有
    	# 三次握手
    	  # 客户端向服务器端发送syn请求,
    	  # 服务端向客户端回复ack并发送syn请求,
    	  # 客户端接收到请求之后再回复ack表示建立连接
    	  # 由客户端的connect + 服务端的accept
    	# 四次挥手
    	  # 客户端向服务端发送fin请求,
    	  # 服务端回复ack确认
    	  # 服务端向客户端发送fin请求,
    	  # 客户端回复ack确认
          # 有客户端的close和服务端的close
    
    • udp(发消息)-在线播放视频qq发消息微信消息
      • 不需要建立连接就可以通信的
      • 不占用连接不可靠(消息因为网络不稳定丢失)快

    最简单的网络通信(基于tcp协议)

    1. 客户端(client):
    import  socket
    
    sk=socket.socket()
    sk.connect(('127.0.0.1',9001))
    
    msg=sk.recv(1024)#最多接受1024个
    print(msg)
    
    sk.send(b'bebebe')
    
    sk.close()
    
    1. 服务端(serve):
    
    import  socket
    
    sk=socket.socket()
    sk.bind(('127.0.0.1',9001))
    sk.listen()
    
    conn,addr=sk.accept()
    conn.send(b'hell')
    msg=conn.recv(1024)#最多接受1024个字节
    print(msg)
    
    conn.close()      #断开连接
    
    sk.close()           #关闭整个serve服务
    

    prat2:

    tcp协议

    • tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端
    1. 服务器端(server):(即可服务器先发送也可客户端先发送)
    import  socket
    sk=socket.socket()
    sk.bind(('127.0.0.1',9001))     #申请操作系统的资源,绑定一个ip 和端口(元组)
    sk.listen()    # 代表socket服务已经开启
    
    print('sk:',sk)
    conn,addr=sk.accept()            #conn里存储的是一个客户端和我serve端的连接信息,等,到有客户端来访问和客户端建立联系
    print('coon:',conn)
    conn.send(b'hello')                 # send直接通过连接发送消息,不需要写地址
    msg=conn.recv(1024)
    print(msg)
    conn.close()    #四次挥手,断开连接
    
    sk.close()    #关闭服务,归还申请的操作系统资源
    
    1. 客户端(client):
    import  socket
    
    sk=socket.socket()
    sk.connect(('127.0.0.1',9001))    # 客户端/tcp协议的方法,和serve端建立连接
    
    msg=sk.recv(1024)    # 只接受消息
    print(msg)
    
    sk.send(b'bebebe')
    
    sk.close()
    

    利用tcp协议和多个客户端进行通信

    1. 服务器端(server):
    sk=socket.socket()
    sk.bind(('127.0.0.1',9001))#申请操作系统的资源
    sk.listen()
    
    while  True:#为了和多个客户端进行握手
    	conn,addr=sk.accept()#能够和多个客户端握手了
    	while  True:#和一个客户使劲聊天
    		send_msg=input('>>>')
    		conn.send(send_msg.encode('utf-8'))
    		if  send_msg.upper()=='Q':break#关闭和该用户通信
    		msg=conn.recv(1024).decode('utf-8')
    		if  msg.upper()=='Q':break
    		print(msg)
    	conn.close()#挥手,断开连接
    
    sk.close()#关闭服务,归还申请的操作系统资源
    
    1. 客户端(client):
    import  socket
    
    sk=socket.socket()
    sk.connect(('127.0.0.1',9001))
    while  True:#和服务器端使劲聊
    	msg=sk.recv(1024).decode('utf-8')
    	if  msg.upper()=='Q':break#关闭和该服务器通信
    	print(msg)
    	send_msg=input('>>>')
    	sk.send(send_msg.encode('utf-8'))
    	if  send_msg.upper()=='Q':break
    sk.close()
    

    struct模块

    import   struct
    #2的23次方都可以转换成4个字节
    num1=129469649
    num2=123
    num3=8
    
    ret1=struct.pack('i',num1)    # 转化为四字节
    print(ret1)
    ret2=struct.pack('i',num2)
    print(ret2)
    ret3=struct.pack('i',num3)
    print(ret3)#返回的是4位字节
    
    print(struct.unpack('i',ret1))   # 解开为原来长度
    print(struct.unpack('i',ret2))
    print(struct.unpack('i',ret3))
    

    黏包现象只发生在tcp协议中:

    1. 从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。
      • 发生在发送端:发送数据小,间隔短。由于优化机制就合并在一起发送了
      • 发生在接受端:接受不及时,所以数据就在接受端的缓存端粘在一起了
    • 粘包现象发生的本质:tcp协议的传输时流式传输,数据之间没有边界
    1. 实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

    解决tcp协议中的粘包现象

    1. 服务器端(server):
    import  struct
    sk=socket.socket()
    sk.bind(('127.0.0.1',9001))#申请操作系统的资源
    sk.listen()
    
    conn,addr=sk.accept()    #conn里存储的是一个客户端和我serve端的连接信息
    
    msg1=input('>>>').encode()
    msg2=input('>>>').encode()
      #num=str(len(msg1))#'6'
      #ret=num.zfill(4)#'0006'
      #conn.send(ret.encode('utf-8'))
    blen=struct.pack('i',len(msg1))
    print(blen)
    conn.send(blen)
    conn.send(msg1)
    conn.send(msg2)
    
    conn.close()#四次挥手,断开连接
    
    sk.close()#关闭服务,归还申请的操作系统资源
    
    1. 客户端(client):
    import  time
    import  socket
    import  struct
    sk=socket.socket()
    sk.connect(('127.0.0.1',9001))
    
    length=sk.recv(4)    # 因为socket发送的是4个字节
    length=struct.unpack('i',length)[0]  #因为其返回的是个元组
    msg1=sk.recv(length)
    print(msg1.decode('utf-8'))
    
    msg2=sk.recv(1024)
    print(msg2.decode('utf-8'))
    sk.close()
    

    解决粘包的本质:设置边界(发送多少个接受多少个)

    • 粘包现象:本来分开的数据粘合到一起去了
    • 只出现在tcp协议中,因为tcp协议多条消息之间没有边界,并且还有一大推优化算法
    • 发送端:两条消息都很短,发送的间隔时间也非常短
    • 接收端:多条消息由于没有及时接受,而在接受方的缓存短,堆在一起导致的粘包
    • tcp协议数据之间没有边界,可以传输大的数据

    udp协议

    • udp是无链接的,启动服务之后可以直接接受消息,不需要提前建立链接(不会粘包)
    1. 服务器端(server):(不需要listen监听)
    import  socket
    #type=socket.SOCK_DGRAM:udp协议          默认是tcp协议
    sk=socket.socket(type=socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1',9001))     #申请操作系统的资源
    while  True:
    	msg,addr=sk.recvfrom(1024)        # 接受消息和地址
    	print(msg.decode('utf-8'))
    	mmsg=input('>>>')
    	sk.sendto(mmsg.encode('utf-8'),addr)      # 需要写一个对方的地址
    sk.close()  # 关闭服务器套接字 #关闭服务,归还申请的操作系统资源
    
    1. 客户端(client):(由客户端发起对话)
    import  socket
    sk=socket.socket(type=socket.SOCK_DGRAM)
    
    serve=('127.0.0.1',9001)
    while  True:
    	mmmsg=input('>><')
    	if  mmmsg.upper()=='Q':break
    	sk.sendto(mmmsg.encode('utf-8'),serve)
    
    	msg=sk.recv(1024).decode('utf-8')
    	if  msg.upper()=='Q':break
    print(msg)
    

    part3:

    验证客户端的合法性

    1. serve端:
    import  socket
    import  os
    import  hashlib
    
    secret_key=b'hahaha'
    sk=socket.socket()
    sk.bind(('127.0.0.1',9001))
    sk.listen()
    
    conn,addr=sk.accept()
    #创建一个随机的字符串
    rand=os.urandom(32)
    #发送随机字符串
    conn.send(rand)
    
    #根据发送的字符串+secretekey进行摘要
    sha=hashlib.sha1(secret_key)
    sha.update(rand)
    res=sha.hexdigest()
    
    #等待接受客户端的摘要结果
    res_client=conn.recv(1024).decode('utf-8')
    #做对比
    if  res_client==res:
    	print('是合法的客户端')
    	conn.send(b'hello')
    else:
    	conn.close()
    #如果不一致,这关闭连接
    
    1. client端:
    import  socket
    import  hashlib
    
    secret_key=b'hahaha'
    sk=socket.socket()
    sk.connect(('127.0.0.1',9001))
    
    #接收客户端发送的随机字符串
    rand=sk.recv(32)
    #根据发送的字符串+secretkey进行摘要
    sha=hashlib.sha1(secret_key)
    sha.update(rand)
    res=sha.hexdigest()
    #摘要结果发送回server端
    sk.send(res.encode('utf-8'))
    #继续和server端进行通信
    msg=sk.recv(1024)
    print(msg)
    
    sk.close()
    

    socketserver模块--针对并发编程

    • socket底层模块
    • socketserver基于socket完成的
    • tcp协议的server端处理并发的客户端请求
    • 例子:网盘:文件的上传和下载
    1. server端:
    import  socketserver
    
    class  Myserver(socketserver.BaseRequestHandler):
    	def  handle(self):
    		conn=self.request
    		while  True:
    			try:
    				content=conn.recv(1024).decode('utf-8')
    				print(content)
    				conn.send(content.upper().encode('utf-8'))
    			except  ConnectionResetError:
    				break
    
    server=socketserver.ThreadingTCPServer(('127.0.0.1',9001),Myserver)
    server.serve_forever()
    
    1. client端:与原来的相同
    import  socket
    sk=socket.socket()
    sk.connect(('127.0.0.1',9001))
    
    while  True:
    	sk.send(b'hello')
    	content=sk.recv(1024).decode('utf-8')
    print(content)
    
  • 相关阅读:
    JS中常见的几种控制台台报错
    nssm常用命令(在Windows系统下安装服务的工具)
    Web前端浏览器默认样式重置(CSS Tools: Reset CSS)
    Layui的本地存储方法-Layui.data的基本使用
    JS事件冒泡与事件捕获怎么理解?
    解决Web开发HTML页面中footer保持在页面底部问题
    cpdetector获取文件编码
    maven
    jdom工具类
    httpclient4封装类
  • 原文地址:https://www.cnblogs.com/zranguai/p/13749752.html
Copyright © 2011-2022 走看看