IPMSG---文件接收流程

来源:互联网 发布:影子网络血腥图 编辑:程序博客网 时间:2024/06/03 16:33
 

1

文件接收端在收到文件信息IPMSG_SENDMSG后

 首先解析存储文件信息

此函数在TRecvDlg的构造函数中

ShareInfo *DecodeShareMsg(char *buf)
{
 ShareInfo *shareInfo = new ShareInfo;
 FileInfo *fileInfo = NULL;
 char  *tok, *p, *p2, *p3;
 char  *file = separate_token(buf, FILELIST_SEPARATOR, &p);

 for (int cnt=0; file; cnt++, file=separate_token(NULL, FILELIST_SEPARATOR, &p))
 {
  ConvertShareMsgEscape(file); // "::" -> ';'
  if ((tok = separate_token(file, ':', &p2)) == NULL)
   break;
  fileInfo = new FileInfo(atoi(tok));

  if ((tok = separate_token(NULL, ':', &p2)) == NULL || strlen(tok) >= MAX_PATH)
   break;
  while ((p3 = strchr(tok, '?')) != NULL) // UNICODE 傑偱偺巄掕
   *p3 = '_';
  fileInfo->SetFname(tok);

  if ((tok = separate_token(NULL, ':', &p2)) == NULL)
   break;
  fileInfo->SetSize(hex2ll(tok));

  if ((tok = separate_token(NULL, ':', &p2)) == NULL)
   break;
  fileInfo->SetMtime(strtoul(tok, 0, 16));

  if ((tok = separate_token(NULL, ':', &p2)))
  {
   fileInfo->SetAttr(strtoul(tok, 0, 16));
   u_int attr_type = GET_MODE(fileInfo->Attr());
   if (attr_type != IPMSG_FILE_DIR && attr_type != IPMSG_FILE_REGULAR)
   {
    delete fileInfo;
    continue;
   }
  }
  //IPMSG_FILE_REGULAR  普通文件
  else fileInfo->SetAttr(IPMSG_FILE_REGULAR);
        //防止内存溢出
  if ((shareInfo->fileCnt % BIG_ALLOC) == 0)
   shareInfo->fileInfo = (FileInfo **)realloc(shareInfo->fileInfo, (shareInfo->fileCnt + BIG_ALLOC) * sizeof(FileInfo *));

  shareInfo->fileInfo[shareInfo->fileCnt++] = fileInfo;
  fileInfo = NULL;
 }
 if (fileInfo) // 僨僐乕僪拞偵敳偗偨
  delete fileInfo;

 if (shareInfo->fileCnt <= 0)
 {
  delete shareInfo;
  return NULL;
 }
 return shareInfo;
}

而后发起对文件发送端的连接

TRecvDlg::SaveFile(void)函数中调用  ConnectRecvFile()

实现对服务器端得连接

连接成功响应 FD_CONNECT

BOOL TRecvDlg::TcpEvent(int sd, LPARAM lParam)
{
 if (WSAGETSELECTERROR(lParam) || fileObj == NULL || fileObj->conInfo == NULL)
  return FALSE;

 switch (LOWORD(lParam))

{

 //connect done 当客户端同服务器端连成功响应 FD_CONNECT 以后开始文件传输
 case FD_CONNECT: 
  StartRecvFile();
  break;

 case FD_CLOSE:
  EndRecvFile();
  break;
 }
 return TRUE;
}

2

BOOL TRecvDlg::StartRecvFile(void)
{

//客户端发送 IPMSG_GETFILEDATA
 char buf[MAX_PATH], tcpbuf[MAX_BUF];

// msg.packetNo 包序号  fileObj->fileInfo->Id() 要传送文件在文件列表中序号
 wsprintf(buf, fileObj->isDir ? "%x:%x:" : "%x:%x:%x:", msg.packetNo, fileObj->fileInfo->Id(), 0);
 fileObj->conInfo->complete = TRUE;
 msgMng->MakeMsg(tcpbuf, fileObj->isDir ? IPMSG_GETDIRFILES : IPMSG_GETFILEDATA, buf);
 msgMng->ConnectDone(hWnd, fileObj->conInfo);

 if (::send(fileObj->conInfo->sd, tcpbuf, strlen(tcpbuf), 0) < (int)strlen(tcpbuf))
  return EndRecvFile(), FALSE;

 fileObj->conInfo->startTick = fileObj->conInfo->lastTick = ::GetTickCount();
 if (fileObj->startTick == 0)
  fileObj->startTick = fileObj->conInfo->startTick;
    //fileObj->isDir 表示是普通文件
 if (fileObj->isDir == FALSE)
  fileObj->curFileInfo = *fileObj->fileInfo;
 fileObj->recvBuf = new char [cfg->TransMax];

 // 0byte file 偩偗偼丄摿椺
 if (fileObj->isDir == FALSE && fileObj->curFileInfo.Size() == 0)
 {
  if (OpenRecvFile() == TRUE)
  {
   CloseRecvFile(TRUE);
   fileObj->status = FS_COMPLETE;
  }
  else fileObj->status = FS_ERROR;

  PostMessage(WM_TCPEVENT, fileObj->conInfo->sd, FD_CLOSE);
  return TRUE;
 }

 DWORD id; // 巊傢偢乮95宯偱 error 偵側傞偺傪杊偖偩偗乯
 fileObj->hThread = ~0; // 旝柇側椞堟傪旔偗傞
 // thread 撪偱偼 MT 懳墳偑昁梫側 crt 偼巊傢偢
 if ((fileObj->hThread = ::CreateThread(NULL, 0, RecvFileThread, this, 0, &id)) == NULL)
 {
  EndRecvFile();
  return FALSE;
 }

 return TRUE;
}

3

DWORD WINAPI TRecvDlg::RecvFileThread(void *_recvDlg)
{
 TRecvDlg *recvDlg = (TRecvDlg *)_recvDlg;
 RecvFileObj *fileObj = recvDlg->fileObj;
 fd_set  rfd;
 tim  tv;
 int   sock_ret;
 BOOL  (TRecvDlg::*RecvFileFunc)(void) =
    fileObj->isDir ? TRecvDlg::RecvDirFile : TRecvDlg::RecvFile;

 FD_ZERO(&rfd);
 FD_SET(fileObj->conInfo->sd, &rfd);

//从连接服务器端成功到开始传输文件本程序的等待时间是 120s

 for (int waitCnt=0; waitCnt < 120 && fileObj->hThread != NULL; waitCnt++)
 {
  tv.tv_sec = 1, tv.tv_usec = 0;
  if ((sock_ret = ::select(fileObj->conInfo->sd + 1, &rfd, NULL, NULL, &tv)) > 0)
  {
   waitCnt = 0;
   if ((recvDlg->*RecvFileFunc)() != TRUE)
    break;
   if (fileObj->status == FS_COMPLETE)
    break;
  }
  else if (sock_ret == 0) {
   FD_ZERO(&rfd);
   FD_SET(fileObj->conInfo->sd, &rfd);
   fileObj->conInfo->lastTick = ::GetTickCount();
   recvDlg->PostMessage(WM_RECVDLG_FILEBUTTON, 0, 0);
  }
  else if (sock_ret == SOCKET_ERROR) {
   break;
  }
 }
 recvDlg->CloseRecvFile(fileObj->status == FS_COMPLETE ? TRUE : FALSE);
 if (fileObj->status != FS_COMPLETE)
  fileObj->status = FS_ERROR;

 recvDlg->PostMessage(WM_TCPEVENT, fileObj->conInfo->sd, FD_CLOSE);
 ::ExitThread(0);
 return 0;
}

BOOL TRecvDlg::CloseRecvFile(BOOL setAttr)
{
 if (fileObj->hFile != INVALID_HANDLE_VALUE)
 {
  if (setAttr)
  {
   FILETIME ft;
   UnixTime2FileTime(fileObj->curFileInfo.Mtime(), &ft);
#if 1 // 巄掕張抲乮protocol format 曄峏偺壜擻惈乯
   if (fileObj->isDir || (fileObj->curFileInfo.Mtime() & 0xffffff00))
#endif
    ::SetFileTime(fileObj->hFile, NULL, &ft, &ft);
  }
  fileObj->totalTrans += fileObj->offset;
  fileObj->totalFiles++;
  fileObj->offset = fileObj->woffset = 0;

  ::CloseHandle(fileObj->hFile);
  fileObj->hFile = INVALID_HANDLE_VALUE;
 }
 return TRUE;
}

***************/////////////////////////////////////////////////*************

BOOL TRecvDlg::RecvFile(void)
{
 int  wresid = (int)(fileObj->offset - fileObj->woffset);
 _int64 remain = fileObj->curFileInfo.Size() - fileObj->offset;
 int  size = 0;

 if (remain > cfg->TransMax - wresid)
  remain = cfg->TransMax - wresid;

 if ((size = ::recv(fileObj->conInfo->sd, fileObj->recvBuf + wresid, (int)remain, 0)) <= 0)
  return FALSE;

 if (fileObj->hFile == INVALID_HANDLE_VALUE)
  if (OpenRecvFile() == FALSE)
   return FALSE;

 wresid += size;
 if (fileObj->offset + size >= fileObj->curFileInfo.Size() || cfg->TransMax == wresid)
 {
  DWORD wsize;
  if (::WriteFile(fileObj->hFile, fileObj->recvBuf, wresid, &wsize, 0) != TRUE || wresid != (int)wsize)
   return MessageBox(WRITEFAIL_MSGSTR), FALSE;
  fileObj->woffset += wresid;
 }
 fileObj->offset += size;

 DWORD nowTick = ::GetTickCount();

 if (nowTick - fileObj->conInfo->lastTick >= 1000)
 {
  fileObj->conInfo->lastTick = nowTick;
  PostMessage(WM_RECVDLG_FILEBUTTON, 0, 0);
 }

 if (fileObj->offset >= fileObj->curFileInfo.Size())
  fileObj->status = fileObj->isDir ? FS_ENDFILE : FS_COMPLETE;

 return TRUE;
}