上一篇博文已经详细介绍tftp协议了,下边联系写一个简单的tftp客户端,首先tftp客户端与服务端通过udp通信,udp不是可靠的通信服务,为了保持通信中数据的可靠传输,我们采用简单的确认机制,服务端对每一个数据报文从01开始编号【0号报文为系统保留】,客户端收到数据报文后,发送确认报文,确认报文应该包含服务器发送报文的编号,这样,当服务端收到确认报文并检查确认数据报文编号,如果是以前发送的最新报文则发送下一个报文,这里需要注意的是,如果服务端在一定时间内没有收到确认报文,则会发生超时,具体超时处理看具体的服务端,一般的默认处理是重新发送报文,当超时次数达到一定的数字,则退出,客户端处理是如果没有收到数据报文,则发送最新收到数据报文的确认报文,如果在一定时间没有收到,则发生超时,通常的超时处理是重新发送最新收到数据报文的确认报文,如果超时次数超过一定的数字,则退出。在tftp通信过程,可以随时的中断通信。这就是tftp通信的整个过程。下边是自己写的一个简单的客户端,没有加入超时机制,只是简单的数据接受。
-
main.c main.h
-
socket_init.c socket_init.h //建立网络连接,
-
file_save.c file_save.c //文件传输
测试命令格式: cmd 192.168.220.63 xxx.xxx
|
网络初始化:
|
文件传输保存:
|
错误一:
|
sock_fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)<0 这个逻辑错误比较隐蔽, '=' 的优先级要小与'<'的优先级,那么执行的结构就是socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)<0这个逻辑式比较的结构存入到sock_fd,而不是把sock()的结构存入到socket_fd中,在求socket_fd<0逻辑式的结构。这个错误的由来是对编写代码不够仔细,对与这个错误还是比较熟悉,往往在写代码时遗漏(),这样加入()后就正常,同时这种类型的逻辑错误编译器是不会报错的,也就是编译是没有问题的,往往是程序运行的结构不对。需要特别的注意逻辑错误。
错误二:
|
recvfromsocket_fd,rec_buf,512,0,&tmp_addr,&len_addr)这条语句会将服务端的信息存入到tmp_addr中,这里的tmp_addr是struct sockaddr 类型的,而struct sockaddr_in类型和struct sockaddr是同大小的,可以之间进行安全的赋值转换,如果tmp_addr是struct sockaddr_in类型的,在recvfrom中需要类型转换(struct sockaddr *),如果不进行格式的转换,编译器换警告,在函数内部会进行自动的类型转换,在发送的时候在使用这个tmp_addr时,tmp_addr内部的转矩其实已经经过两次的类型转换,先从struct sockaddr_in转换为struct sockaddr,在从struct sockaddr 转换为struct sockaddr_in,内部的数据就会发生移位,实际的服务端返回的端口号。 比较安全的方法是使用sruct sockaddr类型,不进行类型的转换。