Part 9.网络编程--TFTP项目,Tcp编程

(一)wireshark抓包工具的使用web

首先,咱们要安装一个wireshark,他是一个抓包工具,方便咱们后面学习下载传送的验证,网上能够很方便下载到,这里再也不赘述。一下是其使用方法:编程

  

  

  

  

  

  

  

以上就是wireshark的基本使用方法。安全

 

(二)应用:TFTP客户端服务器

  1. TFTP协议介绍

TFTP(Trivial File Transfer Protocol,简单文件传输协议网络

是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输的协议socket

特色:tcp

  • 简单
  • 占用资源小
  • 适合传递小文件
  • 适合在局域网进行传递
  • 端口号为69
  • 基于UDP实现

 

  2. TFTP下载过程

TFTP服务器默认监听69号端口工具

当客户端发送“下载”请求(即读请求)时,须要向服务器的69端口发送学习

服务器若批准此请求,则使用一个新的、临时的端口进行数据传输spa

 

当服务器找到须要发送的文件后,会马上打开文件,把文件中的数据经过TFTP协议发送给客户端

若是文件的总大小较大(好比3M),那么服务器分屡次发送,每次会从文件中读取512个字节的数据发送过来

由于发送的次数有可能会不少,因此为了让客户端对接收到的数据进行排序,因此在服务器发送那512个字节数据的时候,会多发2个字节的数据,用来存放序号,而且放在512个字节数据的前面,序号是从1开始的

由于须要从服务器上下载文件时,文件可能不存在,那么此时服务器就会发送一个错误的信息过来,为了区分服务发送的是文件内容仍是错误的提示信息,因此又用了2个字节 来表示这个数据包的功能(称为操做码),而且在序号的前面。

如下为其操做码:

由于udp的数据包不安全,即发送方发送是否成功不能肯定,因此TFTP协议中规定,为了让服务器知道客户端已经接收到了刚刚发送的那个数据包,因此当客户端接收到一个数据包的时候须要向服务器进行发送确认信息,即发送收到了,这样的包成为ACK(应答包)

为了标记数据已经发送完毕,因此规定,当客户端接收到的数据小于516(2字节操做码+2个字节的序号+512字节数据)时,就意味着服务器发送完毕了

 因此,TFTP数据包的格式以下:

  3.参考代码

 1 # -*- coding:utf-8 -*-
 2 
 3 import struct
 4 from socket import *
 5 import time
 6 import os
 7 
 8 def main():
 9 
10 
11     #0. 获取要下载的文件名字:
12     downloadFileName = raw_input("请输入要下载的文件名:")    
13 
14     #1.建立socket
15     udpSocket = socket(AF_INET, SOCK_DGRAM)
16 
17     requestFileData = struct.pack("!H%dsb5sb"%len(downloadFileName), 1, downloadFileName, 0, "octet", 0)
18 
19     #2. 发送下载文件的请求
20     udpSocket.sendto(requestFileData, ("192.168.119.215", 69))
21 
22     flag = True #表示可以下载数据,即不擅长,若是是false那么就删除
23     num = 0
24     f = open(downloadFileName, "w")
25 
26     while True:
27         #3. 接收服务发送回来的应答数据
28         responseData = udpSocket.recvfrom(1024)
29 
30         # print(responseData)
31         recvData, serverInfo = responseData
32 
33         opNum = struct.unpack("!H", recvData[:2])
34 
35         packetNum = struct.unpack("!H", recvData[2:4])
36 
37         print(packetNum[0])
38 
39         # print("opNum=%d"%opNum)
40         # print(opNum)
41 
42         # if 若是服务器发送过来的是文件的内容的话:
43         if opNum[0] == 3: #由于opNum此时是一个元组(3,),因此须要使用下标来提取某个数据
44             
45 
46             #计算出此次应该接收到的文件的序号值,应该是上一次接收到的值的基础上+1
47             num = num + 1
48 
49             # 若是一个下载的文件特别大,即接收到的数据包编号超过了2个字节的大小
50             # 那么会从0继续开始,因此这里须要判断,若是超过了65535 那么就改成0
51             if num==65536:
52                 num = 0
53 
54             # 判断此次接收到的数据的包编号是不是 上一次的包编号的下一个
55             # 若是是才会写入到文件中,不然不能写入(由于会重复)
56             if num == packetNum[0]:
57                 # 把收到的数据写入到文件中
58                 f.write(recvData[4:])
59                 num = packetNum[0]
60 
61             #整理ACK的数据包
62             ackData = struct.pack("!HH", 4, packetNum[0])
63             udpSocket.sendto(ackData, serverInfo)
64 
65         elif opNum[0] == 5:
66             print("sorry,没有这个文件....")
67             flag = False
68 
69         # time.sleep(0.1)
70 
71         if len(recvData)<516:
72             break
73 
74     if flag == True:
75         f.close()
76     else:
77         os.unlink(downloadFileName)#若是没有要下载的文件,那么就须要把刚刚建立的文件进行删除
78 
79 if __name__ == '__main__':
80     main()

 

(三)udp广播

网络编程中的广播便是发送方只需发送一次数据到中间层而后中间层把它给全部该广播地址下的接收方。

咱们前面说的对于一段IP地址:192.168.1.X  其中192.168.1.0表示网络号;192.168.1.255表示广播号。

 1 #coding=utf-8
 2 
 3 import socket, sys
 4 
 5 dest = ('<broadcast>', 7788) #采用<broadcast>这个关键字实现通用的广播地址,就不用特定指定了。
 6 
 7 # 建立udp套接字
 8 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 9 
10 # 对这个须要发送广播数据的套接字进行修改设置,不然不能发送广播数据
11 s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1)
12 
13 # 以广播的形式发送数据到本网络的全部电脑中
14 s.sendto("Hi", dest)
15 
16 print "等待对方回复(按ctrl+c退出)"
17 
18 while True:
19     (buf, address) = s.recvfrom(2048)
20     print "Received from %s: %s" % (address, buf)

 

(四)tcp介绍

tcp:传输控制协议

相对udp传送稳定但速度更慢,目前web服务器广泛使用tcp。

前面咱们学习了udp协议,在udp通讯模型中,在通讯开始以前,不须要创建相关的连接,只须要发送数据便可,相似于生活中,"写信"":其过程以下

 

而在tcp通讯模型中,在通讯开始以前,必定要先创建相关的连接,才能发送数据,相似于生活中,"打电话""。其流程以下:

 

(五)tcp服务器

生活中的电话机:

若是想让别人能更够打通我们的电话获取相应服务的话,须要作一下几件事情:

  1. 买个手机
  2. 插上手机卡
  3. 设计手机为正常接听状态(即可以响铃)
  4. 静静的等着别人拨打

tcp服务器:

如同上面的电话机过程同样,在程序中,若是想要完成一个tcp服务器的功能,须要的流程以下:

  1. socket建立一个套接字——>买个手机
  2. bind绑定ip和port——>插上手机卡
  3. listen使套接字变为能够被动连接——>响铃模式
  4. accept等待客户端的连接——>等待电话
  5. recv/send接收发送数据
 1 #coding=utf-8
 2 from socket import *
 3 
 4 # 建立socket
 5 tcpSerSocket = socket(AF_INET, SOCK_STREAM)
 6 
 7 # 绑定本地信息
 8 address = ('', 7788)
 9 tcpSerSocket.bind(address)
10 
11 # 使用socket建立的套接字默认的属性是主动的,使用listen将其变为被动的,这样就能够接收别人的连接了
12 tcpSerSocket.listen(5)
13 
14 # 若是有新的客户端来连接服务器,那么就产生一个新的套接字专门为这个客户端服务
15 # newSocket用来为这个客户端服务
16 # tcpSerSocket就能够省下来专门等待其余新客户端的连接
17 newSocket, clientAddr = tcpSerSocket.accept()
18 
19 # 接收对方发送过来的数据,最大接收1024个字节
20 recvData = newSocket.recv(1024)
21 print ('接收到的数据为:%s'%recvData)
22 
23 # 发送一些数据到客户端
24 newSocket.send("thank you !")
25 
26 # 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,若是还须要服务,只能再次从新链接
27 newSocket.close()
28 
29 # 关闭监听套接字,只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的链接
30 tcpSerSocket.close()

 

(六)tcp客户端

所谓的服务器端:就是提供服务的一方,而客户端,就是须要被服务的一方

tcp客户端构建流程

tcp的客户端要比服务器端简单不少,若是说服务器端是须要本身买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只须要找一个电话亭,拿起电话拨打便可,流程要少不少。

 

 1 from socket import *
 2 
 3 #建立套接字
 4 clientSocket = socket(AF_INET, SOCK_STREAM)
 5 #进行连接,注意connect参数为一个元组
 6 clientSocket.connect(("192.168.119.153", 8989))
 7 
 8 #注意:
 9 # 1. tcp客户端已经连接好了服务器,因此在之后的数据发送中,不须要填写对方的iph和port----->打电话
10 # 2. udp在发送数据的时候,由于没有以前的连接,所依须要 在每次的发送中 都要填写接收方的ip和port----->写信 
11 clientSocket.send("haha".encode("gb2312"))
12 
13 recvData = clientSocket.recv(1024)
14 
15 print("recvData:%s"%recvData)
16 
17 clientSocket.close()
相关文章
相关标签/搜索