yakin

有了舞台就好好表演,没有舞台就静静地做观众

导航

TFTPserver的实现

TFTP: Trivial File Transfer Protocol
Bootloade中原本用的是TFTP server,但是我们把它改造成client。这样需要在PC端写一个TFTP server。

1) 使用socket。
   在工程里面加一个CTftpServerSocket类,继承自CAsyncSocket。

2) 实现OnReceive函数。
   (这不是最佳实现办法,这样的话server完全是被动的。但是还好,Eboot端实现了重发,所以不会出现丢包后连路断掉的现象)
   void CTftpServerSocket::OnReceive(int nErrorCode)
{
 // TODO: Add your specialized code here and/or call the base class
 unsigned char ReceiveBuf[256];
 unsigned char SendBuf[516];
 int type;
 int DataLen;


    if(!TftpReceive(ReceiveBuf))
 {
  AfxMessageBox("TftpReceive,Failed!");
  return;
 }
 type = JudgeTftpType(ReceiveBuf);
 if(!EncapsulateTftp(type,ReceiveBuf,SendBuf,&DataLen))
 {
  AfxMessageBox("EncapsulateTftp,Failed!");
  return;
 }
 if(DataLen == 512)
 {
  if(BlockNum == 1) //socket=69 only used for waiting tftp request.
  {
   DataChannel->SendTo(SendBuf,sizeof(SendBuf),CTftpServerSocket::TargetPort,
                                            CTftpServerSocket::TargetAddress);
  }
  else
  {
   SendTo(SendBuf,sizeof(SendBuf),CTftpServerSocket::TargetPort,
                                CTftpServerSocket::TargetAddress);
  }
 }
 else if(DataLen < 512)
 {
  unsigned char *TempSendBuf = (unsigned char *)malloc(DataLen + 4);
  //copy data from SendBuf to TempSendBuf.
  //strncpy(TempSendBuf, (char *)SendBuf, DataLen + 4);
  for(int i = 0; i < (DataLen + 4); i++)
  {
   TempSendBuf[i] = SendBuf[i];
  }

  if(BlockNum == 1) //socket=69 only used for waiting tftp request.
  {
   DataChannel->SendTo(TempSendBuf,DataLen + 4,CTftpServerSocket::TargetPort,
                                             CTftpServerSocket::TargetAddress);
  }
  else
  {
   SendTo(TempSendBuf,DataLen + 4,CTftpServerSocket::TargetPort,
                                CTftpServerSocket::TargetAddress);
  }
 }

 if(BlockNum == 1)
 {
  DataChannel->ShowProgress();
 }
 else
 {
  ShowProgress();
 }
 
 CAsyncSocket::OnReceive(nErrorCode);
}

      上面就是TFTP的OnReceive函数实现。
      a) TftpReceive(ReceiveBuf)就是接收包。它还是一个重要功能是识别出接收包源端的port,以便调用SendTo时有明确的目标port。所以接收函数使用的是ReceiveFrom,而不是通常的Receive。
      b) JudgeTftpType(ReceiveBuf)
         TFTP总共有五种格式的包,RRQ,WRQ,DATA,ACK,ERROR,而且格式比TCP简单多了。这个函数的功能是判断这个包的格式,以后为下一步发送包作准备。
      c) EncapsulateTftp(type,ReceiveBuf,SendBuf,&DataLen)
         这个是打包函数。正如我们理解的,当收到ACK包时,反馈DATA包;收到RRQ包时,反馈DATA包等等。所以这个函数根据Type类型,反馈相应的包。我们这个应用肯定收到的是ACK或者RRQ,所以反馈的肯定都是DATA包。这时我们就要读取指定文件的数据,SendBuf就可以成为待发送的包了。下面就可以用SendTo发送到相应IP地址的相应port。
      d) 可以看到当BlockNum为1的时候,总是要用DataChannel->SendTo,这是因为TFTP的69通常就是用来侦听,另外有一个随机端口用来接收和发送数据。所以当BlockNum为1的时候,很明显是由端口号为69的socket收到的,所以要调用另外一个随机端口号的socket发送数据。

posted on 2005-07-20 13:52  yakin  阅读(1202)  评论(0编辑  收藏  举报