python-网络编程-part4

  • IP地址

    • 一个IP地址包括两部分:网络号和主机号,网络号确定局域网,主机号确定局域网内具体某个主机;
    • A-E类地址的固定前缀逐渐增加(0->10->110->1110->11110);
    • C类地址最常见,主机0-255,其中0、255不用做主机号;如果需一个局域网内有很多主机,则可以利用B/A类地址;DE类地址不常用,基本上是保留地址;在这里插入图片描述
    • 私有IP:本地局域网上的IP,内部使用
      • 10.0.0.0 - 10.255.255.255
      • 172.16.0.0 - 172.31.255.255
      • 192.168.0.0 - 192.168.255.255
      • 公有IP:全球访问
    • 127.0.0.1 - 127.255.255.255 用于回路测试,常见的127.0.0.1即本机地址
    • 子网掩码:用于区分网络号和主机号
      • C类子网掩码:255.255.255.0(因为C类地址有3个字节的网络号);其他类推
    • 端口号:用来标记和区分进程
      • 一台主机多个进程,需要不同端口号以便识别这些进程;
      • IP寻找主机,端口号寻找进程;
      • 知名端口:0-1023,如80、22端口;动态端口:1024-65535,动态分配给进程
  • 协议

    • 四层/七层及协议簇在这里插入图片描述
  • socket

    • 应用层-socket-传输层在这里插入图片描述
    • Socket对TCP/IP协议封装,提供API,面向C/S(client/server)
    • 三个步骤:服务器监听,客户端请求,连接确认
    • demo
    import socket
    # AF_INET是IPV4协议,SOCK_STREAM(TCP协议,可靠/较慢) or SOCK_DGRAM(UDP,不可靠/较快)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    
    • UDP — User Data Protocol,用户数据报协议
      • 不建立连接,不保证对方收得到,没有超时重发,因此传输速度很快
      • 常用于语音聊天、简单文件传输
    • TCP — 传输控制协议
      • 建立连接,三次对话(A ask B & B ack A & A confirm)
    • 采用TCP协议的socket只能发给同样使用TCP协议的socket,UDP同理
    • UDP 数据发送demo(使用网络调试助手)
    from socket import *
    s = socket(AF_INET, SOCK_DGRAM)
    # s.bind(("", 8788))
    # IP地址为接收IP地址,50000是自定义测试端口
    s.sendto("hello".encode("gb2312"), ("192.168.1.103", 50000))
    # 接收(一般要绑定一个用于接收的IP和端口)
    s.bind(("", 8788))  # ""不写默认本机;注意如果使用该设置,send时就要先绑定
    recdata = s.recvfrom(2048)  # 2048是可接收字节大小
    print(recdata[0].decode("gb2312"))
    s.close()
    
    • echo服务器:返回接收到的内容
    from socket import *
    e_s = socket(AF_INET, SOCK_DGRAM)
    e_s.bind(("", 8585))
    while True:
    	rd = e_s.recvfrom(1024)  # 接收消息,rd=( msg, (ip, port) )
    	s.sendto(rd[0], rd[1])  # 发送回去
    e_s.close()
    
  • TFTP:Trivial File Transfer Protocol 简单文件传输协议

    • 可以实现简单文件的下载,tftp的端口为69
    • TFTP示意图(图片来自尚学堂)在这里插入图片描述
    • TFTP格式要求在这里插入图片描述
      • 传输结束:客户端接收到 数据块长度小于516 字节的包(包长可能大于516);如果最后刚好是516,则服务器还会发一个0字节长的包;
      • 如何构造 下载请求 数据包(图片来自尚学堂):利用struct包在这里插入图片描述
      • struct模块的使用:在这里插入图片描述
      • 构造下载请求
    from socket import *
    import struct
    udpsock = socket(AF_INET, SOCK_DGRAM)
    server_ip = ""
    package = struct.pack("!H7sb5sb", 1, b"dog.jpg", 0, b"octet", 0)
    # 1、发送下载请求
    udpsock.sendto(package, (server_ip, 69))
    f = open("dog.jpg", "ab")
    while True:
    	# 2、接收数据
    	rd = udpsock.recvfrom(1024)  # 接收数据
    	# 3、分析数据(注意接收到的数据是516字节=2字节操作码+2字节块编号+512字节数据)
    	caozuoma, ack_num = struct.unpack("!HH", rd[0][:4])  # 获取数据块编号
    	rand_port = rd[1][1]  # 服务器当前发送数据的随机端口
    	# 4、判断状态是否异常
    	if int(caozuoma) == 5:
    		print("文件不存在")
    		break
    	print("操作码:%d, ACK:%d,服务器随机端口:%d,数据长度:%d"%(caozuoma, ack_num, rand_port, len(rd[0])))
    	# 5、没有异常则可以写数据
    	f.write(rd[0][4:])
    	# 6、接收完毕则关掉
    	if len(rd[0]) < 516:
    		break
    	# 7、未接收完毕,返回确认
    	ack_data = struct.pack("!HH", 4, ack_num)
    	udpsock.sendto(ack_data, (server_ip, rand_port))
    
  • 广播:UDP数据包发送给某个子网内所有计算机在这里插入图片描述

    from socket import *
    # 发送给交换机(某个子网,由<broadcast>定义的广播地址,子网内所有开放8080端口的计算机都能收到)
    dest = ("<broadcast>", 8080)
    s = socket(AF_INET, SOCK_DGRAM)
    # socket默认不能发送广播消息,需要更改设置
    s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
    
    s.sendto(b"hi", dest)
    # 接收多个反馈消息
    while True:
    	s.recvfrom(1024)
    
  • TCP

    • 三次握手在这里插入图片描述

    • 四次挥手在这里插入图片描述

    • TCP服务器

    from socket import *
    tcp_sock = socket(AF_INET, SOCK_STREAM)
    tcp_sock.bind("", 7788)  # 服务器需绑定IP和端口
    tcp_sock.listen(5)  # 最大等待数5
    tcp_sock_new, client_addr = tcp_sock.accept()  # 等待连接
    
    data = tcp_sock_new.recv(1024)  # 接收数据
    tcp_sock_new.send(b"收到")  # send不用目标地址和端口,因为前面连接时4次握手建立可靠链接了
    
    tcp_sock_new.close()
    tcp_sock.close()
    # ===============================
    # TCP客户端
    from socket import *
    tcp_sock_cli = socket(AF_INET, SOCK_STREAM)  # client
    tcp_sock_cli.connect(("", 7788))  # address(ip, port)
    
    tcp_sock_cli.send(b"你好")
    data = tcp_sock.recv(1024)
    print(data)
    tcp_sock_cli.close()
    
  • 多进程服务器

    from socket import *
    from multiprocessing import *
    from time import sleep
    # 处理客户端请求
    def dealWithClient(sock_new, dest_addr):
    	while True:
    		data = sock_new.recv(1024)
    		if len(data) > 0:
    			print(f"receive from {dest_addr}: {data}")
    		else:  # 客户端发送完毕后,会发送0字节数据包
    			print(f"{dest_addr} 客户端已经关闭")
    			break
    	sock_new.close()  # 注意要关闭
    	
    if __name__ == "__main__":
    	sock_serv = socket(AF_INET, SOCK_STREAM)
    	sock_serv.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)  # 一般不允许重复使用同一个地址
    	sock_serv.bind("", 7788)
    	sock_serv.listen(5)
    	# sock_serv.accept()
    	while True:
    		sock_new, dest_addr = sock_serv.accept()  # 新客户访问前,会阻塞
    		# 创建新进程为新的客户端服务
    		client = Process(target = dealWithClient, args=(sock_new, dest_addr))
    		client.start()
    		# sock_new由client进程保存一份,当前进程的sock_new可以销毁
    		sock_new.close()
    	finally:
    		# 所有客户端服务完毕后,关闭
    		socke_serv.close()
    	
    
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值