相信自己,快乐每一天
分类: LINUX
2013-11-05 09:28:12
TFTP ( Trivial File Transfer Protocol)即简单文件传送协议,是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供简单的、低开销的文件传输服务。tftpd程序就是进行tftp服务的服务程序。
TFTP协议可以参看RFC 1350。
由于这个程序需要inetd程序的配合,而环境比较难搭建,所以对程序的测试比较困难。
TFTP报文格式如下所示:
int peer;
服务连接的套接字。
int rexmtval =TIMEOUT;
程序采用停止和等待的自动请求重发(ARQ)算法,当接受ACK报文或者数据报文的时间超过rexmtval,则认为接受超时,重新开始接受报文过程。
rexmtval一直维持TIMEOUT的值,没有被改变过。
int maxtimeout =5*TIMEOUT;
当接受数据报文或者ACK报文的时候,如果出现超时,则会进入中断处理程序。如果中断次数过多,则timeout会累加rexmtval时间。一旦超时中断过多,导致timeout超过maxtimeout,则程序退出,停止服务。
maxtimeout一直维持5*TIMEOUT的值,没有被改变过。
#define PKTSIZE SEGSIZE+4
如果TFTP报文的操作码是data,表明传输的是0到512字节的数据。
SEGSIZE是TFTP报文的数据的最大长度,即512字节。
由于TFTP报文还包括2字节的操作码和2字节的块编号,所以TFTP数据报文的长度为SEGSIZE+4。
char buf[PKTSIZE];
缓冲空间,在以下的情况下,作为存储TFTP报文的内存空间:
1. 清楚初始时接收的报文。
2. 发送操作码为error类型的TFTP报文。
3. 在文件传输完毕时(上一次接受到的数据不足512字节),尝试接受操作码为data数据类型的TFTP报文,因为服务器传给用户主机的最后一个ACK有可能丢失。
char ackbuf[PKTSIZE];
缓冲空间,在以下的情况下,作为存储TFTP报文的内存空间:
1. 接受操作码为ACK类型的TFTP报文。
2. 发送操作码为ACK类型的TFTP报文。
union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} from;
描述客户连接的地址。
socklen_t fromlen;
from所占的内存空间大小。
#define MAXARG 1
在启动tftpd程序的时候,需要指定ftp文件夹的路径。MAXARG是所能指定文件夹的个数。
char *dirs[MAXARG+1];
dirs[0]里保存了ftp文件夹的路径。
int confirmed;
表明sendmsg函数的选项的MSG_CONFIRM选项是否设置。
如果设置MSG_CONFIRM,则会告诉链路层的传送有了进展:已经接受到对方的一个成功的答复。由于MSG_CONFIRM的这个意义,所以在发送第一个数据是MSG_CONFIRM选项不因该设置,即confirm初始值为0。在成功接受到一个回复之后,confirm则应该设置为MSG_CONFIRM了。
int timeout;
表示由于等待接受超时的时间总和。
当接受数据报文或者ACK报文的时候,如果出现超时,则会进入中断处理程序,将timeout递加rexmtval秒,如果。一旦超时中断过多,导致timeout超过maxtimeout,则程序退出,停止服务。
jmp_buf timeoutbuf;
在发生等待接收超时时,应当将要发送的报文重新发送(报文可能为ACK报文或者data报文)。setjmp()和longjmp()函数就可以用来实现这种跳转的功能。
由于等待超时时会进入计时器中断处理程序,在中断处理程序中调用longjmp()函数来跳转到最后一次用setjmp()设置timeoutbuf的地方运行,也就是重新进行报文的发送。
timeoutbuf就记录了调用setjmp()的时候的程序上下文。
struct bf {
int counter;
charbuf[PKTSIZE];
} bfs[2];
缓冲空间,在以下的情况下,作为存储TFTP报文的内存空间:
1. 接受操作码为data类型的TFTP报文。
2. 发送操作码为data类型的TFTP报文。
counter用来标识存储的缓冲空间的数据是一下三种的哪一种:
1. BF_ALLOC,标识是已经申请的存储空间。
2. BF_FREE,标识存储空间没有使用。
3. 大于0的数,标识里面已经存储数据。
static int nextone;
待使用的下一个缓冲的标号。
static int current;
正在使用的当前缓冲的标号。
int newline = 0;
在数据传输是按照8位的ASCII码形式(netascii)组织的情况下,标识是不是有新的行出现。
在顺次读取或者写入字节流时,如果遇到'\n'或者'\r'字符都会设置newline为1,方便进行特殊处理。
int prevchar = -1; /* putbuf: previous char (cr check) */
在数据传输是按照8位的ASCII码形式(netascii)组织的情况下,记录上个处理的字符。
和newline一样,prevchar是为了处理'\r'或者'\n'的特殊字符。
处理的效果是:
1. 如果要发送'\r'字符则传送的实际是\r\0";如果要发送'\n'字符则传送的实际是"\r\n"。
2. 如果接受到"\r\n",则保存的实际是字符'\n';如果接受到"\r\0",则保存的实际是字符'\r'。