1、鏈接情況介紹
windows
fileserver開始並非和客戶端鏈接的,客戶端是按需鏈接file_server的。可是file_server與msg_server倒是長鏈接。先啓動file_server,再啓動msg_server。msg_server初始化的時候,會去嘗試鏈接file_server的8601端口。鏈接成功之後,會給file_server發送一個發包詢問file_server偵聽客戶端鏈接的ip和端口號信息:服務器
- void CFileServConn::OnConfirm()
- {
- log("connect to file server success ");
- m_bOpen = true;
- m_connect_time = get_tick_count();
- g_file_server_list[m_serv_idx].reconnect_cnt = MIN_RECONNECT_CNT / 2;
-
-
- IM::Server::IMFileServerIPReq msg;
- CImPdu pdu;
- pdu.SetPBMsg(&msg);
- pdu.SetServiceId(SID_OTHER);
- pdu.SetCommandId(CID_OTHER_FILE_SERVER_IP_REQ);
- SendPdu(&pdu);
- }
file_server收到該數據包後,將本身的偵聽客戶端鏈接的ip地址和端口號發包告訴msg_server:
- void FileMsgServerConn::_HandleGetServerAddressReq(CImPdu* pPdu) {
- IM::Server::IMFileServerIPRsp msg;
-
- const std::list<IM::BaseDefine::IpAddr>& addrs = ConfigUtil::GetInstance()->GetAddressList();
-
- for (std::list<IM::BaseDefine::IpAddr>::const_iterator it=addrs.begin(); it!=addrs.end(); ++it) {
- IM::BaseDefine::IpAddr* addr = msg.add_ip_addr_list();
- *addr = *it;
- log("Upload file_client_conn addr info, ip=%s, port=%d", addr->ip().c_str(), addr->port());
- }
-
- SendMessageLite(this, SID_OTHER, CID_OTHER_FILE_SERVER_IP_RSP, pPdu->GetSeqNum(), &msg);
- }
獲得的信息是file_server偵聽的ip地址和端口號,默認配置的端口號是8600。也就是說file_server的8600用於客戶端鏈接,8601端口用於msg_server鏈接。這樣,客戶端須要傳輸文件(注意:不是聊天圖片,聊天圖片使用另一個服務msfs進行傳輸),會先告訴msg_server它須要進行文件傳輸,msg_server收到消息後告訴客戶端,你連file_server來傳輸文件吧,並把file_server的地址和端口號告訴客戶端。客戶端這個時候鏈接file_server進行文件傳輸。咱們來具體看一看這個流程的細節信息:
1. 客戶端發包給msg_server說要進行文件發送併發

而後選擇一個文件:dom

pc客戶端發送文件邏輯:ide
-
- void SessionLayout::Notify(TNotifyUI& msg)
- {
- ...
-
- else if (msg.pSender == m_pBtnsendfile)
- {
- module::UserInfoEntity userInfo;
- if (!module::getUserListModule()->getUserInfoBySId(m_sId, userInfo))
- {
- LOG__(ERR, _T("SendFile can't find the sid"));
- return;
- }
-
- CFileDialog fileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST
- , _T("文件|*.*||"), AfxGetMainWnd());
- fileDlg.m_ofn.Flags |= OFN_NOCHANGEDIR;
- fileDlg.DoModal();
-
- CString sPathName;
- POSITION nPos = fileDlg.GetStartPosition();
- if (nPos != NULL)
- {
- sPathName = fileDlg.GetNextPathName(nPos);
- }
- if (sPathName.IsEmpty())
- return;
-
- module::getFileTransferModule()->sendFile(sPathName, m_sId, userInfo.isOnlne());
- }
- ...
-
- }
sPathName是文件的全飾路徑;m_sId是收取文件的用戶id,userInfo.isOnlne()判斷m_sId表明的用戶是否在線,以此來決定此次文件傳輸是在線文件仍是離線文件模式。
- BOOL FileTransferModule_Impl::sendFile(IN const CString& sFilePath, IN const std::string& sSendToSID,IN BOOL bOnlineMode)
- {
- if (TransferFileEntityManager::getInstance()->checkIfIsSending(sFilePath))
- {
- return FALSE;
- }
- TransferFileEntity fileEntity;
-
-
- struct __stat64 buffer;
- _wstat64(sFilePath, &buffer);
- fileEntity.nFileSize = (UInt32)buffer.st_size;
- if (0 != fileEntity.nFileSize)
- {
- CString strFileName = sFilePath;
- strFileName.Replace(_T("\\"), _T("/"));
- fileEntity.sFileName = util::cStringToString(strFileName);
- fileEntity.sFromID = module::getSysConfigModule()->userID();
- fileEntity.sToID = sSendToSID;
- uint32_t transMode = 0;
- transMode = bOnlineMode ? IM::BaseDefine::TransferFileType::FILE_TYPE_ONLINE : IM::BaseDefine::TransferFileType::FILE_TYPE_OFFLINE;
-
- LOG__(DEBG,_T("FileTransferSevice_Impl::sendFile sTaskID = %s"), util::stringToCString(fileEntity.sTaskID));
-
- imcore::IMLibCoreStartOperationWithLambda(
- [=]()
- {
- IM::File::IMFileReq imFileReq;
- LOG__(APP, _T("imFileReq,name=%s,size=%d,toId=%s"),util::stringToCString(fileEntity.sFileName)
- ,fileEntity.nFileSize,util::stringToCString(fileEntity.sToID));
- imFileReq.set_from_user_id(util::stringToInt32(fileEntity.sFromID));
- imFileReq.set_to_user_id(util::stringToInt32(fileEntity.sToID));
- imFileReq.set_file_name(fileEntity.sFileName);
- imFileReq.set_file_size(fileEntity.nFileSize);
- imFileReq.set_trans_mode(static_cast<IM::BaseDefine::TransferFileType>(transMode));
-
- module::getTcpClientModule()->sendPacket(IM::BaseDefine::ServiceID::SID_FILE
- , IM::BaseDefine::FileCmdID::CID_FILE_REQUEST
- , &imFileReq);
- });
-
- return TRUE;
- }
- LOG__(ERR, _T("fileEntity FileSize error,size = %d"), fileEntity.nFileSize);
- return FALSE;
- }
上面代碼中組裝的包信息中含有要傳輸的文件路徑、文件大小、發送人id、接收方id、文件傳輸模式(在線仍是離線),包的命令號是IM::BaseDefine::FileCmdID::CID_FILE_REQUEST。這個包發給msg_server之後,msg_server應答:
- void CMsgConn::HandlePdu(CImPdu* pPdu)
- {
- ...
-
- case CID_FILE_REQUEST:
- s_file_handler->HandleClientFileRequest(this, pPdu);
- break;
- ...
-
- }
- void CFileHandler::HandleClientFileRequest(CMsgConn* pMsgConn, CImPdu* pPdu)
- {
- IM::File::IMFileReq msg;
- CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()));
-
- uint32_t from_id = pMsgConn->GetUserId();
- uint32_t to_id = msg.to_user_id();
- string file_name = msg.file_name();
- uint32_t file_size = msg.file_size();
- uint32_t trans_mode = msg.trans_mode();
- log("HandleClientFileRequest, %u->%u, fileName: %s, trans_mode: %u.", from_id, to_id, file_name.c_str(), trans_mode);
-
- CDbAttachData attach(ATTACH_TYPE_HANDLE, pMsgConn->GetHandle());
- CFileServConn* pFileConn = get_random_file_serv_conn();
- if (pFileConn)
- {
- IM::Server::IMFileTransferReq msg2;
- msg2.set_from_user_id(from_id);
- msg2.set_to_user_id(to_id);
- msg2.set_file_name(file_name);
- msg2.set_file_size(file_size);
- msg2.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- msg2.set_attach_data(attach.GetBuffer(), attach.GetLength());
- CImPdu pdu;
- pdu.SetPBMsg(&msg2);
- pdu.SetServiceId(SID_OTHER);
- pdu.SetCommandId(CID_OTHER_FILE_TRANSFER_REQ);
- pdu.SetSeqNum(pPdu->GetSeqNum());
-
- if (IM::BaseDefine::FILE_TYPE_OFFLINE == trans_mode)
- {
- pFileConn->SendPdu(&pdu);
- }
- else
- {
- CImUser* pUser = CImUserManager::GetInstance()->GetImUserById(to_id);
- if (pUser && pUser->GetPCLoginStatus())
- {
- pFileConn->SendPdu(&pdu);
- }
- else
- {
-
- CPduAttachData attach_data(ATTACH_TYPE_HANDLE_AND_PDU_FOR_FILE, pMsgConn->GetHandle(), pdu.GetBodyLength(), pdu.GetBodyData());
- IM::Buddy::IMUsersStatReq msg3;
- msg3.set_user_id(from_id);
- msg3.add_user_id_list(to_id);
- msg3.set_attach_data(attach_data.GetBuffer(), attach_data.GetLength());
- CImPdu pdu2;
- pdu2.SetPBMsg(&msg3);
- pdu2.SetServiceId(SID_BUDDY_LIST);
- pdu2.SetCommandId(CID_BUDDY_LIST_USERS_STATUS_REQUEST);
- pdu2.SetSeqNum(pPdu->GetSeqNum());
- CRouteServConn* route_conn = get_route_serv_conn();
- if (route_conn)
- {
- route_conn->SendPdu(&pdu2);
- }
- }
- }
- }
- else
- {
- log("HandleClientFileRequest, no file server. ");
- IM::File::IMFileRsp msg2;
- msg2.set_result_code(1);
- msg2.set_from_user_id(from_id);
- msg2.set_to_user_id(to_id);
- msg2.set_file_name(file_name);
- msg2.set_task_id("");
- msg2.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- CImPdu pdu;
- pdu.SetPBMsg(&msg2);
- pdu.SetServiceId(SID_FILE);
- pdu.SetCommandId(CID_FILE_RESPONSE);
- pdu.SetSeqNum(pPdu->GetSeqNum());
- pMsgConn->SendPdu(&pdu);
- }
- }
這段代碼,頗有講究,msg_server會檢測file_server是否已經啓動,若是沒有啓動,則直接發包告訴客戶端,file_server不存在。另外,若是該文件傳輸模式是在線文件,會判斷接收文件的用戶是否和發送用戶在同一臺msg_server上。不在的話,則給route_server發送消息,查找該用戶所在的msg_server(這個不具體介紹了,後面分析route_server會專門介紹的)。不然,會將文件發送請求轉發給file_server,包的命令號是CID_OTHER_FILE_TRANSFER_REQ。file_server收到該請求後,處理以下:
- void FileMsgServerConn::HandlePdu(CImPdu* pdu) {
-
- ...
-
- case CID_OTHER_FILE_TRANSFER_REQ:
- _HandleMsgFileTransferReq(pdu);
- break ;
- ...
-
- }
- void FileMsgServerConn::_HandleMsgFileTransferReq(CImPdu* pdu) {
- IM::Server::IMFileTransferReq transfer_req;
- CHECK_PB_PARSE_MSG(transfer_req.ParseFromArray(pdu->GetBodyData(), pdu->GetBodyLength()));
-
-
- uint32_t from_id = transfer_req.from_user_id();
- uint32_t to_id = transfer_req.to_user_id();
-
- IM::Server::IMFileTransferRsp transfer_rsp;
- transfer_rsp.set_result_code(1);
- transfer_rsp.set_from_user_id(from_id);
- transfer_rsp.set_to_user_id(to_id);
- transfer_rsp.set_file_name(transfer_req.file_name());
- transfer_rsp.set_file_size(transfer_req.file_size());
- transfer_rsp.set_task_id("");
- transfer_rsp.set_trans_mode(transfer_req.trans_mode());
- transfer_rsp.set_attach_data(transfer_req.attach_data());
-
-
- bool rv = false;
- do {
- std::string task_id = GenerateUUID();
- if (task_id.empty()) {
- log("Create task id failed");
- break;
- }
- log("trams_mode=%d, task_id=%s, from_id=%d, to_id=%d, file_name=%s, file_size=%d", transfer_req.trans_mode(), task_id.c_str(), from_id, to_id, transfer_req.file_name().c_str(), transfer_req.file_size());
-
- BaseTransferTask* transfer_task = TransferTaskManager::GetInstance()->NewTransferTask(
- transfer_req.trans_mode(),
- task_id,
- from_id,
- to_id,
- transfer_req.file_name(),
- transfer_req.file_size());
-
- if (transfer_task == NULL) {
-
-
-
- log("Create task failed");
- break;
- }
-
- transfer_rsp.set_result_code(0);
- transfer_rsp.set_task_id(task_id);
- rv = true;
-
-
- log("Create task succeed, task id %s, task type %d, from user %d, to user %d", task_id.c_str(), transfer_req.trans_mode(), from_id, to_id);
- } while (0);
-
- ::SendMessageLite(this, SID_OTHER, CID_OTHER_FILE_TRANSFER_RSP, pdu->GetSeqNum(), &transfer_rsp);
-
- if (!rv) {
-
- Close();
- }
- }
上述代碼會爲本次傳輸任務建立一個惟一的標識uuid做爲taskid,而後根據離線文件仍是在線文件建立離線文件傳輸任務OfflineTransferTask或者在線文件傳輸任務OnlineTransferTask,並加入一個一個成員變量transfer_tasks_中進行管理:
- BaseTransferTask* TransferTaskManager::NewTransferTask(uint32_t trans_mode, const std::string& task_id, uint32_t from_user_id, uint32_t to_user_id, const std::string& file_name, uint32_t file_size) {
- BaseTransferTask* transfer_task = NULL;
-
- TransferTaskMap::iterator it = transfer_tasks_.find(task_id);
- if (it==transfer_tasks_.end()) {
- if (trans_mode == IM::BaseDefine::FILE_TYPE_ONLINE) {
- transfer_task = new OnlineTransferTask(task_id, from_user_id, to_user_id, file_name, file_size);
- } else if (trans_mode == IM::BaseDefine::FILE_TYPE_OFFLINE) {
- transfer_task = new OfflineTransferTask(task_id, from_user_id, to_user_id, file_name, file_size);
- } else {
- log("Invalid trans_mode = %d", trans_mode);
- }
-
- if (transfer_task) {
- transfer_tasks_.insert(std::make_pair(task_id, transfer_task));
- }
- } else {
- log("Task existed by task_id=%s, why?????", task_id.c_str());
- }
-
- return transfer_task;
- }
這個map transfer_tasks_是在定時器裏面進行按期處理的,處理的依據是當前任務的狀態,好比已經完成的任務就能夠從map中移除了:
- void TransferTaskManager::OnTimer(uint64_t tick) {
- for (TransferTaskMap::iterator it = transfer_tasks_.begin(); it != transfer_tasks_.end();) {
- BaseTransferTask* task = it->second;
- if (task == NULL) {
- transfer_tasks_.erase(it++);
- continue;
- }
-
- if (task->state() != kTransferTaskStateWaitingUpload &&
- task->state() == kTransferTaskStateTransferDone) {
- long esp = time(NULL) - task->create_time();
- if (esp > ConfigUtil::GetInstance()->GetTaskTimeout()) {
- if (task->GetFromConn()) {
- FileClientConn* conn = reinterpret_cast<FileClientConn*>(task->GetFromConn());
- conn->ClearTransferTask();
- }
- if (task->GetToConn()) {
- FileClientConn* conn = reinterpret_cast<FileClientConn*>(task->GetToConn());
- conn->ClearTransferTask();
- }
- delete task;
- transfer_tasks_.erase(it++);
- continue;
- }
- }
-
- ++it;
- }
- }
完成這些工做之後,組裝的應答包命令號是CID_OTHER_FILE_TRANSFER_RSP,回覆給msg_server。msg_server收到該應答包後處理:
- void CFileServConn::HandlePdu(CImPdu* pPdu)
- {
- switch (pPdu->GetCommandId()) {
- ...
-
- case CID_OTHER_FILE_TRANSFER_RSP:
- _HandleFileMsgTransRsp(pPdu);
- break;
- ...
-
- }
- }
- void CFileServConn::_HandleFileMsgTransRsp(CImPdu* pPdu)
- {
- IM::Server::IMFileTransferRsp msg;
- CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()));
-
- uint32_t result = msg.result_code();
- uint32_t from_id = msg.from_user_id();
- uint32_t to_id = msg.to_user_id();
- string file_name = msg.file_name();
- uint32_t file_size = msg.file_size();
- string task_id = msg.task_id();
- uint32_t trans_mode = msg.trans_mode();
- CDbAttachData attach((uchar_t*)msg.attach_data().c_str(), msg.attach_data().length());
- log("HandleFileMsgTransRsp, result: %u, from_user_id: %u, to_user_id: %u, file_name: %s, \
- task_id: %s, trans_mode: %u. ", result, from_id, to_id,
- file_name.c_str(), task_id.c_str(), trans_mode);
-
- const list<IM::BaseDefine::IpAddr>* ip_addr_list = GetFileServerIPList();
-
- IM::File::IMFileRsp msg2;
- msg2.set_result_code(result);
- msg2.set_from_user_id(from_id);
- msg2.set_to_user_id(to_id);
- msg2.set_file_name(file_name);
- msg2.set_task_id(task_id);
- msg2.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- for (list<IM::BaseDefine::IpAddr>::const_iterator it = ip_addr_list->begin(); it != ip_addr_list->end(); it++)
- {
- IM::BaseDefine::IpAddr ip_addr_tmp = *it;
- IM::BaseDefine::IpAddr* ip_addr = msg2.add_ip_addr_list();
- ip_addr->set_ip(ip_addr_tmp.ip());
- ip_addr->set_port(ip_addr_tmp.port());
- }
- CImPdu pdu;
- pdu.SetPBMsg(&msg2);
- pdu.SetServiceId(SID_FILE);
- pdu.SetCommandId(CID_FILE_RESPONSE);
- pdu.SetSeqNum(pPdu->GetSeqNum());
- uint32_t handle = attach.GetHandle();
-
- CMsgConn* pFromConn = CImUserManager::GetInstance()->GetMsgConnByHandle(from_id, handle);
- if (pFromConn)
- {
- pFromConn->SendPdu(&pdu);
- }
-
- if (result == 0)
- {
- IM::File::IMFileNotify msg3;
- msg3.set_from_user_id(from_id);
- msg3.set_to_user_id(to_id);
- msg3.set_file_name(file_name);
- msg3.set_file_size(file_size);
- msg3.set_task_id(task_id);
- msg3.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- msg3.set_offline_ready(0);
- for (list<IM::BaseDefine::IpAddr>::const_iterator it = ip_addr_list->begin(); it != ip_addr_list->end(); it++)
- {
- IM::BaseDefine::IpAddr ip_addr_tmp = *it;
- IM::BaseDefine::IpAddr* ip_addr = msg3.add_ip_addr_list();
- ip_addr->set_ip(ip_addr_tmp.ip());
- ip_addr->set_port(ip_addr_tmp.port());
- }
- CImPdu pdu2;
- pdu2.SetPBMsg(&msg3);
- pdu2.SetServiceId(SID_FILE);
- pdu2.SetCommandId(CID_FILE_NOTIFY);
-
-
- CImUser* pToUser = CImUserManager::GetInstance()->GetImUserById(to_id);
- if (pToUser)
- {
- pToUser->BroadcastPduWithOutMobile(&pdu2);
- }
-
-
- CRouteServConn* pRouteConn = get_route_serv_conn();
- if (pRouteConn) {
- pRouteConn->SendPdu(&pdu2);
- }
- }
- }
msg_server收到包後,首先裝包數據,並把file_server的ip地址和端口信息帶上,發給請求發文件的客戶端,命令號是CID_FILE_RESPONSE;接着查詢通知接收方有人給其發文件(通知方式也是同樣,若是接收方在該msg_server上,直接發給該用戶;不在的話,發給路由服務route_server)。固然接收到文件發送的端只有pc端,移動端會被過濾掉的,也就是說移動端不會收到發送文件的請求。
咱們先看發送方pc客戶端收到應答的邏輯(命令號是CID_FILE_RESPONSE):函數
- void FileTransferModule_Impl::onPacket(imcore::TTPBHeader& header, std::string& pbBody)
- {
- switch (header.getCommandId())
- {
- case IM::BaseDefine::FileCmdID::CID_FILE_RESPONSE:
- _sendfileResponse(pbBody);
- break;
- }
- }
- void FileTransferModule_Impl::_sendfileResponse(IN std::string& body)
- {
- IM::File::IMFileRsp imFileRsp;
- if (!imFileRsp.ParseFromString(body))
- {
- LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body));
- return;
- }
-
- UInt32 nResult = imFileRsp.result_code();
- if (nResult != 0)
- {
- LOG__(ERR, _T("_sendfileResponse result != 0"));
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_UPLOAD_FAILED);
- }
-
- TransferFileEntity fileEntity;
- fileEntity.sTaskID = imFileRsp.task_id();
- assert(!fileEntity.sTaskID.empty());
- fileEntity.sFromID = util::uint32ToString(imFileRsp.from_user_id());
- fileEntity.sToID = util::uint32ToString(imFileRsp.to_user_id());
- fileEntity.sFileName = imFileRsp.file_name();
- fileEntity.setSaveFilePath(util::stringToCString(fileEntity.sFileName));
- fileEntity.time = static_cast<UInt32>(time(0));
- uint32_t transMode = imFileRsp.trans_mode();
- if (IM::BaseDefine::TransferFileType::FILE_TYPE_ONLINE == transMode)
- {
- fileEntity.nClientMode = IM::BaseDefine::ClientFileRole::CLIENT_REALTIME_SENDER;
- }
- else if (IM::BaseDefine::TransferFileType::FILE_TYPE_OFFLINE == transMode)
- {
- fileEntity.nClientMode = IM::BaseDefine::ClientFileRole::CLIENT_OFFLINE_UPLOAD;
- }
- fileEntity.pFileObject = new TransferFile(util::stringToCString(fileEntity.sFileName),FALSE);
- if (fileEntity.pFileObject)
- {
- fileEntity.nFileSize = fileEntity.pFileObject->length();
- }
-
- UINT32 nIPCount = imFileRsp.ip_addr_list_size();
- if (nIPCount <= 0)
- {
- return;
- }
- const IM::BaseDefine::IpAddr& ipAdd = imFileRsp.ip_addr_list(0);
- fileEntity.sIP = ipAdd.ip();
- fileEntity.nPort = ipAdd.port();
-
- if (!TransferFileEntityManager::getInstance()->pushTransferFileEntity(fileEntity))
- TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);
-
- LOG__(DEBG, _T("FileTransferSevice_Impl::準備鏈接文件服務器 sTaskId = %s"), util::stringToCString(fileEntity.sTaskID));
- TransferFileEntityManager::getInstance()->openFileSocketByTaskId(fileEntity.sTaskID);
- }
客戶端在TransferFileEntityManager::getInstance()->openFileSocketByTaskId(fileEntity.sTaskID);裏面實際去鏈接file_server並嘗試發文件:
- void TransferFileEntityManager::openFileSocketByTaskId(std::string& taskId)
- {
- m_fileUIThread->openFileSocketByTaskId(taskId);
- }
- void FileTransferUIThread::openFileSocketByTaskId(std::string& taskId)
- {
- FileTransferSocket* pFileSocket = _findFileSocketByTaskId(taskId);
- if (!pFileSocket)
- {
- pFileSocket = new FileTransferSocket(taskId);
- m_lstFileTransSockets.push_back(pFileSocket);
- assert(m_hWnd);
- ::PostMessage(m_hWnd, WM_FILE_TRANSFER, 0, (LPARAM)pFileSocket);
- }
- }
- LRESULT _stdcall FileTransferUIThread::_WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
- {
- if (WM_FILE_TRANSFER == message)
- {
- FileTransferSocket* pFileSocket = (FileTransferSocket*)lparam;
- pFileSocket->startFileTransLink();
- }
-
- return ::DefWindowProc(hWnd, message, wparam, lparam);
- }
- BOOL FileTransferSocket::startFileTransLink()
- {
- TransferFileEntity FileInfo;
- if (TransferFileEntityManager::getInstance()->getFileInfoByTaskId(m_sTaskId, FileInfo))
- {
-
- LOG__(APP, _T("connect IP=%s,Port=%d"), util::stringToCString(FileInfo.sIP), FileInfo.nPort);
- connect(util::stringToCString(FileInfo.sIP), FileInfo.nPort);
-
- return TRUE;
- }
- LOG__(ERR, _T("can't find the TaskId"));
- return FALSE;
- }
注意,這裏只是去鏈接file_server服務器,鏈接成功的狀況下,會嘗試登陸文件服務器,登陸file_server的命令號是CID_FILE_LOGIN_REQ:
- void FileTransferSocket::onConnectDone()
- {
- LOG__(APP, _T("FileTransferSocket::onConnected()"));
- startHeartbeat();
-
- TransferFileEntity info;
- if (!TransferFileEntityManager::getInstance()->getFileInfoByTaskId(m_sTaskId, info))
- {
- LOG__(APP, _T("Can't get the file info,task id:%s"),util::stringToCString(m_sTaskId));
- return;
- }
-
-
- IM::File::IMFileLoginReq imFileLoginReq;
- imFileLoginReq.set_user_id(module::getSysConfigModule()->userId());
- imFileLoginReq.set_task_id(info.sTaskID);
- imFileLoginReq.set_file_role(static_cast<IM::BaseDefine::ClientFileRole>(info.nClientMode));
-
- LOG__(APP, _T("IMFileLoginReq,sTaskID:%s,nClientMode:%d"), util::stringToCString(info.sTaskID), info.nClientMode);
-
- LOG__(APP, _T("IMFileLoginReq,taskId:%s"), util::stringToCString(info.sTaskID));
- sendPacket(IM::BaseDefine::ServiceID::SID_FILE, IM::BaseDefine::FileCmdID::CID_FILE_LOGIN_REQ, &imFileLoginReq);
-
-
-
-
- }
file_server收到該數據包處理以下:
- void FileClientConn::HandlePdu(CImPdu* pdu) {
-
- ...
-
- case CID_FILE_LOGIN_REQ:
- _HandleClientFileLoginReq(pdu);
- break;
- }
- void FileClientConn::_HandleClientFileLoginReq(CImPdu* pdu) {
- IM::File::IMFileLoginReq login_req;
- CHECK_PB_PARSE_MSG(login_req.ParseFromArray(pdu->GetBodyData(), pdu->GetBodyLength()));
-
- uint32_t user_id = login_req.user_id();
- string task_id = login_req.task_id();
- IM::BaseDefine::ClientFileRole mode = login_req.file_role();
-
- log("Client login, user_id=%d, task_id=%s, file_role=%d", user_id, task_id.c_str(), mode);
-
- BaseTransferTask* transfer_task = NULL;
-
- bool rv = false;
- do {
-
- transfer_task = TransferTaskManager::GetInstance()->FindByTaskID(task_id);
-
- if (transfer_task == NULL) {
- if (mode == CLIENT_OFFLINE_DOWNLOAD) {
-
-
- transfer_task = TransferTaskManager::GetInstance()->NewTransferTask(task_id, user_id);
-
- if (transfer_task == NULL) {
- log("Find task id failed, user_id=%u, taks_id=%s, mode=%d", user_id, task_id.c_str(), mode);
- break;
- }
- } else {
- log("Can't find task_id, user_id=%u, taks_id=%s, mode=%d", user_id, task_id.c_str(), mode);
- break;
- }
- }
-
-
- rv = transfer_task->ChangePullState(user_id, mode);
- if (!rv) {
-
- break;
-
- }
-
-
- auth_ = true;
- transfer_task_ = transfer_task;
- user_id_ = user_id;
-
- transfer_task->SetConnByUserID(user_id, this);
- rv = true;
-
- } while (0);
-
- IM::File::IMFileLoginRsp login_rsp;
- login_rsp.set_result_code(rv?0:1);
- login_rsp.set_task_id(task_id);
-
- ::SendMessageLite(this, SID_FILE, CID_FILE_LOGIN_RES, pdu->GetSeqNum(), &login_rsp);
-
- if (rv) {
- if (transfer_task->GetTransMode() == FILE_TYPE_ONLINE) {
- if (transfer_task->state() == kTransferTaskStateWaitingTransfer) {
- CImConn* conn = transfer_task_->GetToConn();
- if (conn) {
- _StatesNotify(CLIENT_FILE_PEER_READY, task_id, transfer_task_->from_user_id(), conn);
- } else {
- log("to_conn is close, close me!!!");
- Close();
- }
-
-
- }
- } else {
- if (transfer_task->state() == kTransferTaskStateWaitingUpload) {
-
- OfflineTransferTask* offline = reinterpret_cast<OfflineTransferTask*>(transfer_task);
-
- IM::File::IMFilePullDataReq pull_data_req;
- pull_data_req.set_task_id(task_id);
- pull_data_req.set_user_id(user_id);
- pull_data_req.set_trans_mode(FILE_TYPE_OFFLINE);
- pull_data_req.set_offset(0);
- pull_data_req.set_data_size(offline->GetNextSegmentBlockSize());
-
- ::SendMessageLite(this, SID_FILE, CID_FILE_PULL_DATA_REQ, &pull_data_req);
-
- log("Pull Data Req");
- }
- }
- } else {
- Close();
- }
- }
file_server應答客戶端的命令號是CID_FILE_LOGIN_RES,客戶端收到該包後處理以下:ui
- void FileTransferSocket::onReceiveData(const char* data, int32_t size)
- {
- std::string pbBody;
- imcore::TTPBHeader pbHeader;
- try
- {
- pbHeader.unSerialize((byte*)data, imcore::HEADER_LENGTH);
- pbBody.assign(data + imcore::HEADER_LENGTH, size - imcore::HEADER_LENGTH);
-
- if (IM::BaseDefine::OtherCmdID::CID_OTHER_HEARTBEAT == pbHeader.getCommandId()
- && IM::BaseDefine::ServiceID::SID_OTHER == pbHeader.getModuleId())
- return;
- }
- catch (CPduException e)
- {
- LOG__(ERR, _T("onPacket CPduException serviceId:%d,commandId:%d,errCode:%d")
- , e.GetModuleId(), e.GetCommandId(), e.GetErrorCode());
- return;
- }
- catch (...)
- {
- LOG__(ERR, _T("FileTransferSocket onPacket unknown exception"));
- return;
- }
- UInt16 ncmdid = pbHeader.getCommandId();
- switch (ncmdid)
- {
- case IM::BaseDefine::FileCmdID::CID_FILE_LOGIN_RES:
- _fileLoginResponse(pbBody);
- break;
-
- }
- }
- void FileTransferSocket::_fileLoginResponse(IN std::string& body)
- {
- IM::File::IMFileLoginRsp imFileLoginRsp;
- if (!imFileLoginRsp.ParseFromString(body))
- {
- LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body));
- return;
- }
- if (imFileLoginRsp.result_code() != 0)
- {
- LOG__(ERR, _T("file server login failed! "));
- return;
- }
-
- std::string taskId = imFileLoginRsp.task_id();
- TransferFileEntity fileEntity;
- if (!TransferFileEntityManager::getInstance()->getFileInfoByTaskId(taskId, fileEntity))
- {
- LOG__(ERR, _T("file server login:can't find the fileInfo "));
- return;
- }
-
- LOG__(APP, _T("IMFileLoginRsp, file server login succeed"));
-
- if (IM::BaseDefine::ClientFileRole::CLIENT_REALTIME_SENDER == fileEntity.nClientMode
- || IM::BaseDefine::ClientFileRole::CLIENT_OFFLINE_UPLOAD == fileEntity.nClientMode)
- {
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILETRANSFER_SENDFILE, fileEntity.sTaskID);
- }
- else if (IM::BaseDefine::ClientFileRole::CLIENT_REALTIME_RECVER == fileEntity.nClientMode
- || IM::BaseDefine::ClientFileRole::CLIENT_OFFLINE_DOWNLOAD == fileEntity.nClientMode)
- {
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILETRANSFER_REQUEST, fileEntity.sTaskID);
- }
- }
至此,不論是離線文件仍是在線文件發送,pc客戶端會顯示一個文件進度的對話框:

對於在線文件,須要對端贊成接收文件的傳輸,客戶端纔會讀取文件,這個進度條纔會發生變化。而對於離線文件,應該會立馬讀取文件上傳文件數據到服務器。但是哪裏會觸發客戶端讀取文件併發送的邏輯呢?門道在於file_server在收到登陸請求CID_FILE_LOGIN_REQ後,不只會給客戶端發送登陸應答數據包CID_FILE_LOGIN_RES。還會根據文件的傳輸模式,若是是離線文件則會給客戶端發送拉取文件的數據包CID_FILE_PULL_DATA_REQ,代碼咱們已經在上面的FileClientConn::_HandleClientFileLoginReq(CImPdu* pdu)中貼過了,咱們再貼一次:this
- void FileClientConn::_HandleClientFileLoginReq(CImPdu* pdu) {
- IM::File::IMFileLoginReq login_req;
- CHECK_PB_PARSE_MSG(login_req.ParseFromArray(pdu->GetBodyData(), pdu->GetBodyLength()));
-
- uint32_t user_id = login_req.user_id();
- string task_id = login_req.task_id();
- IM::BaseDefine::ClientFileRole mode = login_req.file_role();
-
- log("Client login, user_id=%d, task_id=%s, file_role=%d", user_id, task_id.c_str(), mode);
-
- BaseTransferTask* transfer_task = NULL;
-
- bool rv = false;
- do {
-
- transfer_task = TransferTaskManager::GetInstance()->FindByTaskID(task_id);
-
- if (transfer_task == NULL) {
- if (mode == CLIENT_OFFLINE_DOWNLOAD) {
-
-
- transfer_task = TransferTaskManager::GetInstance()->NewTransferTask(task_id, user_id);
-
- if (transfer_task == NULL) {
- log("Find task id failed, user_id=%u, taks_id=%s, mode=%d", user_id, task_id.c_str(), mode);
- break;
- }
- } else {
- log("Can't find task_id, user_id=%u, taks_id=%s, mode=%d", user_id, task_id.c_str(), mode);
- break;
- }
- }
-
-
- rv = transfer_task->ChangePullState(user_id, mode);
- if (!rv) {
-
- break;
-
- }
-
-
- auth_ = true;
- transfer_task_ = transfer_task;
- user_id_ = user_id;
-
- transfer_task->SetConnByUserID(user_id, this);
- rv = true;
-
- } while (0);
-
- IM::File::IMFileLoginRsp login_rsp;
- login_rsp.set_result_code(rv?0:1);
- login_rsp.set_task_id(task_id);
-
- ::SendMessageLite(this, SID_FILE, CID_FILE_LOGIN_RES, pdu->GetSeqNum(), &login_rsp);
-
- if (rv) {
- if (transfer_task->GetTransMode() == FILE_TYPE_ONLINE) {
- if (transfer_task->state() == kTransferTaskStateWaitingTransfer) {
- CImConn* conn = transfer_task_->GetToConn();
- if (conn) {
- _StatesNotify(CLIENT_FILE_PEER_READY, task_id, transfer_task_->from_user_id(), conn);
- } else {
- log("to_conn is close, close me!!!");
- Close();
- }
-
-
- }
- } else {
- if (transfer_task->state() == kTransferTaskStateWaitingUpload) {
-
- OfflineTransferTask* offline = reinterpret_cast<OfflineTransferTask*>(transfer_task);
-
- IM::File::IMFilePullDataReq pull_data_req;
- pull_data_req.set_task_id(task_id);
- pull_data_req.set_user_id(user_id);
- pull_data_req.set_trans_mode(FILE_TYPE_OFFLINE);
- pull_data_req.set_offset(0);
- pull_data_req.set_data_size(offline->GetNextSegmentBlockSize());
-
- ::SendMessageLite(this, SID_FILE, CID_FILE_PULL_DATA_REQ, &pull_data_req);
-
- log("Pull Data Req");
- }
- }
- } else {
- Close();
- }
- }
pc端收到CID_FILE_PULL_DATA_REQ後,表示這是一個離線文件,就能夠直接上傳文件數據了:
- case IM::BaseDefine::FileCmdID::CID_FILE_PULL_DATA_REQ:
- _filePullDataReqResponse(pbBody);
- void FileTransferSocket::_filePullDataReqResponse(IN std::string& body)
- {
- IM::File::IMFilePullDataReq imFilePullDataReq;
- if (!imFilePullDataReq.ParseFromString(body))
- {
- LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body));
- return;
- }
- UInt32 fileSize = imFilePullDataReq.data_size();
- UInt32 fileOffset = imFilePullDataReq.offset();
- std::string taskId = imFilePullDataReq.task_id();
-
- TransferFileEntity fileEntity;
- if (!TransferFileEntityManager::getInstance()->getFileInfoByTaskId(taskId, fileEntity))
- {
- LOG__(ERR, _T("PullDataReqResponse: can't find the fileInfo"));
- return;
- }
- LOG__(DEBG, _T("send:taskId=%s,filesize=%d,name=%s,BolckSize=%d")
- ,util::stringToCString(fileEntity.sTaskID)
- ,fileEntity.nFileSize
- ,fileEntity.getRealFileName()
- ,fileSize);
- std::string buff;
- if (nullptr == fileEntity.pFileObject)
- {
- LOG__(ERR, _T("PullDataReqResponse: file boject Destoryed!"));
- return;
- }
- fileEntity.pFileObject->readBlock(fileOffset, fileSize, buff);
- IM::File::IMFilePullDataRsp imFilePullDataRsp;
- imFilePullDataRsp.set_result_code(0);
- imFilePullDataRsp.set_task_id(taskId);
- imFilePullDataRsp.set_user_id(util::stringToInt32(fileEntity.sFromID));
- imFilePullDataRsp.set_offset(fileOffset);
- imFilePullDataRsp.set_file_data((void*)buff.data(), fileSize);
-
-
- sendPacket(IM::BaseDefine::ServiceID::SID_FILE, IM::BaseDefine::FileCmdID::CID_FILE_PULL_DATA_RSP
- , &imFilePullDataRsp);
-
- fileEntity.nProgress = fileOffset + fileSize;
- if (fileEntity.nProgress < fileEntity.nFileSize)
- {
-
- TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_UPDATA_PROGRESSBAR
- , fileEntity.sTaskID);
- }
- else
- {
- if (fileEntity.pFileObject)
- {
- delete fileEntity.pFileObject;
- fileEntity.pFileObject = nullptr;
- }
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_PROGRESSBAR_FINISHED
- , fileEntity.sTaskID);
- }
- TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);
- }
固然,若是文件比較大,一次發不完也不要緊,在CID_FILE_PULL_DATA_REQ中有當前文件的偏移量,客戶端在讀取文件和應答服務器時也帶上這個偏移量fileOffset,應答給服務器的包是CID_FILE_PULL_DATA_RSP。file_server收到應答後處理:
- void FileClientConn::HandlePdu(CImPdu* pdu) {
-
- ...
-
- case CID_FILE_PULL_DATA_RSP:
- _HandleClientFilePullFileRsp( pdu);
- break ;
- ...
-
-
- }
- void FileClientConn::_HandleClientFilePullFileRsp(CImPdu *pdu) {
- if (!auth_ || !transfer_task_) {
- log("auth is false");
- return;
- }
-
-
- IM::File::IMFilePullDataRsp pull_data_rsp;
- CHECK_PB_PARSE_MSG(pull_data_rsp.ParseFromArray(pdu->GetBodyData(), pdu->GetBodyLength()));
-
- uint32_t user_id = pull_data_rsp.user_id();
- string task_id = pull_data_rsp.task_id();
- uint32_t offset = pull_data_rsp.offset();
- uint32_t data_size = static_cast<uint32_t>(pull_data_rsp.file_data().length());
- const char* data = pull_data_rsp.file_data().data();
-
-
- log("Recv FilePullFileRsp, task_id=%s, user_id=%u, offset=%u, data_size=%d", task_id.c_str(), user_id, offset, data_size);
-
- int rv = -1;
- do {
-
-
- if (user_id != user_id_) {
- log("Received user_id valid, recv_user_id = %d, transfer_task.user_id = %d, user_id_ = %d", user_id, transfer_task_->from_user_id(), user_id_);
- break;
- }
-
-
- if (transfer_task_->task_id() != task_id) {
- log("Received task_id valid, recv_task_id = %s, this_task_id = %s", task_id.c_str(), transfer_task_->task_id().c_str());
-
- break;
- }
-
- rv = transfer_task_->DoRecvData(user_id, offset, data, data_size);
- if (rv == -1) {
- break;
- }
-
- if (transfer_task_->GetTransMode() == FILE_TYPE_ONLINE) {
-
- OnlineTransferTask* online = reinterpret_cast<OnlineTransferTask*>(transfer_task_);
- pdu->SetSeqNum(online->GetSeqNum());
-
-
- CImConn* conn = transfer_task_->GetToConn();
- if (conn) {
- conn->SendPdu(pdu);
- }
- } else {
-
-
- if (rv == 1) {
- _StatesNotify(CLIENT_FILE_DONE, task_id, user_id, this);
-
- } else {
- OfflineTransferTask* offline = reinterpret_cast<OfflineTransferTask*>(transfer_task_);
-
- IM::File::IMFilePullDataReq pull_data_req;
- pull_data_req.set_task_id(task_id);
- pull_data_req.set_user_id(user_id);
- pull_data_req.set_trans_mode(static_cast<IM::BaseDefine::TransferFileType>(offline->GetTransMode()));
- pull_data_req.set_offset(offline->GetNextOffset());
- pull_data_req.set_data_size(offline->GetNextSegmentBlockSize());
-
- ::SendMessageLite(this, SID_FILE, CID_FILE_PULL_DATA_REQ, &pull_data_req);
-
- }
- }
-
- } while (0);
-
- if (rv!=0) {
-
-
- Close();
- }
- }
若是是在線文件,就直接轉發含有文件數據的包;若是是離線文件,則存入文件服務上,即寫入文件:
- int OfflineTransferTask::DoRecvData(uint32_t user_id, uint32_t offset, const char* data, uint32_t data_size) {
-
-
- int rv = -1;
-
- do {
-
- if (!CheckFromUserID(user_id)) {
- log("rsp user_id=%d, but sender_id is %d", user_id, from_user_id_);
- break;
- }
-
-
- if (state_ != kTransferTaskStateWaitingUpload && state_ != kTransferTaskStateUploading) {
- log("state=%d error, need kTransferTaskStateWaitingUpload or kTransferTaskStateUploading", state_);
- break;
- }
-
-
- if (offset != transfered_idx_*SEGMENT_SIZE) {
- break;
- }
-
-
-
-
-
-
-
- data_size = GetNextSegmentBlockSize();
- log("Ready recv data, offset=%d, data_size=%d, segment_size=%d", offset, data_size, sengment_size_);
-
- if (state_ == kTransferTaskStateWaitingUpload) {
- if (fp_ == NULL) {
- fp_ = OpenByWrite(task_id_, to_user_id_);
- if (fp_ == NULL) {
- break;
- }
- }
-
-
- OfflineFileHeader file_header;
- memset(&file_header, 0, sizeof(file_header));
- file_header.set_create_time(time(NULL));
- file_header.set_task_id(task_id_);
- file_header.set_from_user_id(from_user_id_);
- file_header.set_to_user_id(to_user_id_);
- file_header.set_file_name("");
- file_header.set_file_size(file_size_);
- fwrite(&file_header, 1, sizeof(file_header), fp_);
- fflush(fp_);
-
- state_ = kTransferTaskStateUploading;
- }
-
-
- if (fp_ == NULL) {
-
- break;
- }
-
- fwrite(data, 1, data_size, fp_);
- fflush(fp_);
-
- ++transfered_idx_;
- SetLastUpdateTime();
-
- if (transfered_idx_ == sengment_size_) {
- state_ = kTransferTaskStateUploadEnd;
- fclose(fp_);
- fp_ = NULL;
- rv = 1;
- } else {
- rv = 0;
- }
- } while (0);
-
- return rv;
- }
如此循環,直至文件傳輸完成。固然文件上傳完成後file_server也會斷開與客戶端的鏈接。
到這裏咱們介紹了發送文件方的邏輯,下面咱們看看接收方的邏輯,上文中介紹了接收方會收到接收文件的通知CID_FILE_NOTIFY,客戶端處理這個命令號:spa
- case IM::BaseDefine::FileCmdID::CID_FILE_NOTIFY:
- <span style="white-space:pre"> </span>_fileNotify(pbBody);
- void FileTransferModule_Impl::_fileNotify(IN std::string& body)
- {
- IM::File::IMFileNotify imFileNotify;
- if (!imFileNotify.ParseFromString(body))
- {
- LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body));
- return;
- }
- TransferFileEntity file;
- file.sFileName = imFileNotify.file_name();
- file.sFromID = util::uint32ToString(imFileNotify.from_user_id());
- file.sToID = util::uint32ToString(imFileNotify.to_user_id());
- file.sTaskID = imFileNotify.task_id();
- file.nFileSize = imFileNotify.file_size();
-
- UINT32 nIPCount = imFileNotify.ip_addr_list_size();
- if (nIPCount <= 0)
- {
- return;
- }
- const IM::BaseDefine::IpAddr& ipAdd = imFileNotify.ip_addr_list(0);
- file.sIP = ipAdd.ip();
- file.nPort = ipAdd.port();
-
- uint32_t transMode = imFileNotify.trans_mode();
- if (IM::BaseDefine::TransferFileType::FILE_TYPE_ONLINE == transMode)
- {
- file.nClientMode = IM::BaseDefine::ClientFileRole::CLIENT_REALTIME_RECVER;
- }
- else if (IM::BaseDefine::TransferFileType::FILE_TYPE_OFFLINE == transMode)
- {
- file.nClientMode = IM::BaseDefine::ClientFileRole::CLIENT_OFFLINE_DOWNLOAD;
- }
- file.time = static_cast<UInt32>(time(0));
- TransferFileEntityManager::getInstance()->pushTransferFileEntity(file);
- LOG__(DEBG, _T("FileTransferSevice_Impl::給你發文件 sFileID = %s"), util::stringToCString(file.sTaskID));
-
- if (1 == imFileNotify.offline_ready())
- {
-
- }
-
-
- TransferFileEntityManager::getInstance()->openFileSocketByTaskId(file.sTaskID);
- }
其實也就是接收方會去鏈接文件服務器。鏈接成功之後,在對應的回調函數裏面觸發顯示接收文件對話框。可是此時實際上還不能接收文件,由於發送方可能還沒準備好。發送方要準備啥呢?前面咱們已經介紹了,咱們梳理一下上述流程:
1. 發送方先向msg_server請求發送文件,msg_server轉發給file_server;.net
2. file_server應答msg_server並告訴msg_server本身的地址和端口號;
3. msg_server收到file_server的應答後,先回復發送方,再轉發給接收方;
4. 發送方接着發送登陸請求給file_server,file_server收到請求決定是否給發送方發送拉取文件的數據包。若是是離線文件,則會馬上給發送方發送拉取文件的數據包;若是是在線文件,則須要等待接收方贊成接收。
因此,必須過了步驟4,一直到file_server應答了發送方的登陸文件服務器請求後,發送方纔算準備好。此時,file_server知道發送方已經準備好了,給接收方發送數據包CID_FILE_STATE。接收方收到這個命令號後:
- case IM::BaseDefine::FileCmdID::CID_FILE_STATE:
- _fileState(pbBody);
- void FileTransferSocket::_fileState(IN std::string& body)
- {
- IM::File::IMFileState imFileState;
- if (!imFileState.ParseFromString(body))
- {
- LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body));
- return;
- }
- UINT32 nfileState = imFileState.state();
-
- std::string taskId = imFileState.task_id();
- TransferFileEntity fileEntity;
- if (!TransferFileEntityManager::getInstance()->getFileInfoByTaskId(taskId, fileEntity))
- {
- LOG__(ERR, _T("fileState:can't find the fileInfo "));
- return;
- }
-
- switch (nfileState)
- {
- case IM::BaseDefine::ClientFileState::CLIENT_FILE_PEER_READY:
- LOG__(APP, _T("fileState--CLIENT_FILE_PEER_READY "));
- break;
- case IM::BaseDefine::ClientFileState::CLIENT_FILE_CANCEL :
- LOG__(APP, _T("fileState--CLIENT_FILE_CANCEL "));
- {
- if (fileEntity.pFileObject)
- {
- delete fileEntity.pFileObject;
- fileEntity.pFileObject = nullptr;
- }
- TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_UPLOAD_CANCEL, fileEntity.sTaskID);
- }
- break;
- case IM::BaseDefine::ClientFileState::CLIENT_FILE_REFUSE:
- LOG__(APP, _T("fileState--CLIENT_FILE_REFUSE "));
- {
- if (fileEntity.pFileObject)
- {
- delete fileEntity.pFileObject;
- fileEntity.pFileObject = nullptr;
- }
- TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_UPLOAD_REJECT, fileEntity.sTaskID);
- }
- break;
- case IM::BaseDefine::ClientFileState::CLIENT_FILE_DONE:
- LOG__(APP, _T("fileState--CLIENT_FILE_DONE "));
- if (fileEntity.pFileObject)
- {
- delete fileEntity.pFileObject;
- fileEntity.pFileObject = nullptr;
- }
- TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_PROGRESSBAR_FINISHED, fileEntity.sTaskID);
- break;
- default:
- break;
- }
- }
同理,對於接收方,選擇接收仍是拒絕文件的邏輯也是在這裏一塊兒處理的,與此相似,這裏就再也不重複敘述了。
接收方下載文件的邏輯和發送方上傳文件的邏輯相似。這裏也不在描述了。
最後說一點個人建議,teamtalk的file_server邏輯、以及與客戶端還有msg_server的邏輯流程加上各類細節寫的比較的細膩,代碼實現上也比較好。強烈建議好好地閱讀這部分的代碼。畢竟不少人在本身實現一個文件服務器時,仍是存在很多問題的。
zhangyl 2017.05.20
文中若是存在說的不對的地方,歡迎批評指正。
1、鏈接情況介紹
fileserver開始並非和客戶端鏈接的,客戶端是按需鏈接file_server的。可是file_server與msg_server倒是長鏈接。先啓動file_server,再啓動msg_server。msg_server初始化的時候,會去嘗試鏈接file_server的8601端口。鏈接成功之後,會給file_server發送一個發包詢問file_server偵聽客戶端鏈接的ip和端口號信息:
- void CFileServConn::OnConfirm()
- {
- log("connect to file server success ");
- m_bOpen = true;
- m_connect_time = get_tick_count();
- g_file_server_list[m_serv_idx].reconnect_cnt = MIN_RECONNECT_CNT / 2;
-
-
- IM::Server::IMFileServerIPReq msg;
- CImPdu pdu;
- pdu.SetPBMsg(&msg);
- pdu.SetServiceId(SID_OTHER);
- pdu.SetCommandId(CID_OTHER_FILE_SERVER_IP_REQ);
- SendPdu(&pdu);
- }
file_server收到該數據包後,將本身的偵聽客戶端鏈接的ip地址和端口號發包告訴msg_server:
- void FileMsgServerConn::_HandleGetServerAddressReq(CImPdu* pPdu) {
- IM::Server::IMFileServerIPRsp msg;
-
- const std::list<IM::BaseDefine::IpAddr>& addrs = ConfigUtil::GetInstance()->GetAddressList();
-
- for (std::list<IM::BaseDefine::IpAddr>::const_iterator it=addrs.begin(); it!=addrs.end(); ++it) {
- IM::BaseDefine::IpAddr* addr = msg.add_ip_addr_list();
- *addr = *it;
- log("Upload file_client_conn addr info, ip=%s, port=%d", addr->ip().c_str(), addr->port());
- }
-
- SendMessageLite(this, SID_OTHER, CID_OTHER_FILE_SERVER_IP_RSP, pPdu->GetSeqNum(), &msg);
- }
獲得的信息是file_server偵聽的ip地址和端口號,默認配置的端口號是8600。也就是說file_server的8600用於客戶端鏈接,8601端口用於msg_server鏈接。這樣,客戶端須要傳輸文件(注意:不是聊天圖片,聊天圖片使用另一個服務msfs進行傳輸),會先告訴msg_server它須要進行文件傳輸,msg_server收到消息後告訴客戶端,你連file_server來傳輸文件吧,並把file_server的地址和端口號告訴客戶端。客戶端這個時候鏈接file_server進行文件傳輸。咱們來具體看一看這個流程的細節信息:
1. 客戶端發包給msg_server說要進行文件發送

而後選擇一個文件:

pc客戶端發送文件邏輯:
-
- void SessionLayout::Notify(TNotifyUI& msg)
- {
- ...
-
- else if (msg.pSender == m_pBtnsendfile)
- {
- module::UserInfoEntity userInfo;
- if (!module::getUserListModule()->getUserInfoBySId(m_sId, userInfo))
- {
- LOG__(ERR, _T("SendFile can't find the sid"));
- return;
- }
-
- CFileDialog fileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST
- , _T("文件|*.*||"), AfxGetMainWnd());
- fileDlg.m_ofn.Flags |= OFN_NOCHANGEDIR;
- fileDlg.DoModal();
-
- CString sPathName;
- POSITION nPos = fileDlg.GetStartPosition();
- if (nPos != NULL)
- {
- sPathName = fileDlg.GetNextPathName(nPos);
- }
- if (sPathName.IsEmpty())
- return;
-
- module::getFileTransferModule()->sendFile(sPathName, m_sId, userInfo.isOnlne());
- }
- ...
-
- }
sPathName是文件的全飾路徑;m_sId是收取文件的用戶id,userInfo.isOnlne()判斷m_sId表明的用戶是否在線,以此來決定此次文件傳輸是在線文件仍是離線文件模式。
- BOOL FileTransferModule_Impl::sendFile(IN const CString& sFilePath, IN const std::string& sSendToSID,IN BOOL bOnlineMode)
- {
- if (TransferFileEntityManager::getInstance()->checkIfIsSending(sFilePath))
- {
- return FALSE;
- }
- TransferFileEntity fileEntity;
-
-
- struct __stat64 buffer;
- _wstat64(sFilePath, &buffer);
- fileEntity.nFileSize = (UInt32)buffer.st_size;
- if (0 != fileEntity.nFileSize)
- {
- CString strFileName = sFilePath;
- strFileName.Replace(_T("\\"), _T("/"));
- fileEntity.sFileName = util::cStringToString(strFileName);
- fileEntity.sFromID = module::getSysConfigModule()->userID();
- fileEntity.sToID = sSendToSID;
- uint32_t transMode = 0;
- transMode = bOnlineMode ? IM::BaseDefine::TransferFileType::FILE_TYPE_ONLINE : IM::BaseDefine::TransferFileType::FILE_TYPE_OFFLINE;
-
- LOG__(DEBG,_T("FileTransferSevice_Impl::sendFile sTaskID = %s"), util::stringToCString(fileEntity.sTaskID));
-
- imcore::IMLibCoreStartOperationWithLambda(
- [=]()
- {
- IM::File::IMFileReq imFileReq;
- LOG__(APP, _T("imFileReq,name=%s,size=%d,toId=%s"),util::stringToCString(fileEntity.sFileName)
- ,fileEntity.nFileSize,util::stringToCString(fileEntity.sToID));
- imFileReq.set_from_user_id(util::stringToInt32(fileEntity.sFromID));
- imFileReq.set_to_user_id(util::stringToInt32(fileEntity.sToID));
- imFileReq.set_file_name(fileEntity.sFileName);
- imFileReq.set_file_size(fileEntity.nFileSize);
- imFileReq.set_trans_mode(static_cast<IM::BaseDefine::TransferFileType>(transMode));
-
- module::getTcpClientModule()->sendPacket(IM::BaseDefine::ServiceID::SID_FILE
- , IM::BaseDefine::FileCmdID::CID_FILE_REQUEST
- , &imFileReq);
- });
-
- return TRUE;
- }
- LOG__(ERR, _T("fileEntity FileSize error,size = %d"), fileEntity.nFileSize);
- return FALSE;
- }
上面代碼中組裝的包信息中含有要傳輸的文件路徑、文件大小、發送人id、接收方id、文件傳輸模式(在線仍是離線),包的命令號是IM::BaseDefine::FileCmdID::CID_FILE_REQUEST。這個包發給msg_server之後,msg_server應答:
- void CMsgConn::HandlePdu(CImPdu* pPdu)
- {
- ...
-
- case CID_FILE_REQUEST:
- s_file_handler->HandleClientFileRequest(this, pPdu);
- break;
- ...
-
- }
- void CFileHandler::HandleClientFileRequest(CMsgConn* pMsgConn, CImPdu* pPdu)
- {
- IM::File::IMFileReq msg;
- CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()));
-
- uint32_t from_id = pMsgConn->GetUserId();
- uint32_t to_id = msg.to_user_id();
- string file_name = msg.file_name();
- uint32_t file_size = msg.file_size();
- uint32_t trans_mode = msg.trans_mode();
- log("HandleClientFileRequest, %u->%u, fileName: %s, trans_mode: %u.", from_id, to_id, file_name.c_str(), trans_mode);
-
- CDbAttachData attach(ATTACH_TYPE_HANDLE, pMsgConn->GetHandle());
- CFileServConn* pFileConn = get_random_file_serv_conn();
- if (pFileConn)
- {
- IM::Server::IMFileTransferReq msg2;
- msg2.set_from_user_id(from_id);
- msg2.set_to_user_id(to_id);
- msg2.set_file_name(file_name);
- msg2.set_file_size(file_size);
- msg2.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- msg2.set_attach_data(attach.GetBuffer(), attach.GetLength());
- CImPdu pdu;
- pdu.SetPBMsg(&msg2);
- pdu.SetServiceId(SID_OTHER);
- pdu.SetCommandId(CID_OTHER_FILE_TRANSFER_REQ);
- pdu.SetSeqNum(pPdu->GetSeqNum());
-
- if (IM::BaseDefine::FILE_TYPE_OFFLINE == trans_mode)
- {
- pFileConn->SendPdu(&pdu);
- }
- else
- {
- CImUser* pUser = CImUserManager::GetInstance()->GetImUserById(to_id);
- if (pUser && pUser->GetPCLoginStatus())
- {
- pFileConn->SendPdu(&pdu);
- }
- else
- {
-
- CPduAttachData attach_data(ATTACH_TYPE_HANDLE_AND_PDU_FOR_FILE, pMsgConn->GetHandle(), pdu.GetBodyLength(), pdu.GetBodyData());
- IM::Buddy::IMUsersStatReq msg3;
- msg3.set_user_id(from_id);
- msg3.add_user_id_list(to_id);
- msg3.set_attach_data(attach_data.GetBuffer(), attach_data.GetLength());
- CImPdu pdu2;
- pdu2.SetPBMsg(&msg3);
- pdu2.SetServiceId(SID_BUDDY_LIST);
- pdu2.SetCommandId(CID_BUDDY_LIST_USERS_STATUS_REQUEST);
- pdu2.SetSeqNum(pPdu->GetSeqNum());
- CRouteServConn* route_conn = get_route_serv_conn();
- if (route_conn)
- {
- route_conn->SendPdu(&pdu2);
- }
- }
- }
- }
- else
- {
- log("HandleClientFileRequest, no file server. ");
- IM::File::IMFileRsp msg2;
- msg2.set_result_code(1);
- msg2.set_from_user_id(from_id);
- msg2.set_to_user_id(to_id);
- msg2.set_file_name(file_name);
- msg2.set_task_id("");
- msg2.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- CImPdu pdu;
- pdu.SetPBMsg(&msg2);
- pdu.SetServiceId(SID_FILE);
- pdu.SetCommandId(CID_FILE_RESPONSE);
- pdu.SetSeqNum(pPdu->GetSeqNum());
- pMsgConn->SendPdu(&pdu);
- }
- }
這段代碼,頗有講究,msg_server會檢測file_server是否已經啓動,若是沒有啓動,則直接發包告訴客戶端,file_server不存在。另外,若是該文件傳輸模式是在線文件,會判斷接收文件的用戶是否和發送用戶在同一臺msg_server上。不在的話,則給route_server發送消息,查找該用戶所在的msg_server(這個不具體介紹了,後面分析route_server會專門介紹的)。不然,會將文件發送請求轉發給file_server,包的命令號是CID_OTHER_FILE_TRANSFER_REQ。file_server收到該請求後,處理以下:
- void FileMsgServerConn::HandlePdu(CImPdu* pdu) {
-
- ...
-
- case CID_OTHER_FILE_TRANSFER_REQ:
- _HandleMsgFileTransferReq(pdu);
- break ;
- ...
-
- }
- void FileMsgServerConn::_HandleMsgFileTransferReq(CImPdu* pdu) {
- IM::Server::IMFileTransferReq transfer_req;
- CHECK_PB_PARSE_MSG(transfer_req.ParseFromArray(pdu->GetBodyData(), pdu->GetBodyLength()));
-
-
- uint32_t from_id = transfer_req.from_user_id();
- uint32_t to_id = transfer_req.to_user_id();
-
- IM::Server::IMFileTransferRsp transfer_rsp;
- transfer_rsp.set_result_code(1);
- transfer_rsp.set_from_user_id(from_id);
- transfer_rsp.set_to_user_id(to_id);
- transfer_rsp.set_file_name(transfer_req.file_name());
- transfer_rsp.set_file_size(transfer_req.file_size());
- transfer_rsp.set_task_id("");
- transfer_rsp.set_trans_mode(transfer_req.trans_mode());
- transfer_rsp.set_attach_data(transfer_req.attach_data());
-
-
- bool rv = false;
- do {
- std::string task_id = GenerateUUID();
- if (task_id.empty()) {
- log("Create task id failed");
- break;
- }
- log("trams_mode=%d, task_id=%s, from_id=%d, to_id=%d, file_name=%s, file_size=%d", transfer_req.trans_mode(), task_id.c_str(), from_id, to_id, transfer_req.file_name().c_str(), transfer_req.file_size());
-
- BaseTransferTask* transfer_task = TransferTaskManager::GetInstance()->NewTransferTask(
- transfer_req.trans_mode(),
- task_id,
- from_id,
- to_id,
- transfer_req.file_name(),
- transfer_req.file_size());
-
- if (transfer_task == NULL) {
-
-
-
- log("Create task failed");
- break;
- }
-
- transfer_rsp.set_result_code(0);
- transfer_rsp.set_task_id(task_id);
- rv = true;
-
-
- log("Create task succeed, task id %s, task type %d, from user %d, to user %d", task_id.c_str(), transfer_req.trans_mode(), from_id, to_id);
- } while (0);
-
- ::SendMessageLite(this, SID_OTHER, CID_OTHER_FILE_TRANSFER_RSP, pdu->GetSeqNum(), &transfer_rsp);
-
- if (!rv) {
-
- Close();
- }
- }
上述代碼會爲本次傳輸任務建立一個惟一的標識uuid做爲taskid,而後根據離線文件仍是在線文件建立離線文件傳輸任務OfflineTransferTask或者在線文件傳輸任務OnlineTransferTask,並加入一個一個成員變量transfer_tasks_中進行管理:
- BaseTransferTask* TransferTaskManager::NewTransferTask(uint32_t trans_mode, const std::string& task_id, uint32_t from_user_id, uint32_t to_user_id, const std::string& file_name, uint32_t file_size) {
- BaseTransferTask* transfer_task = NULL;
-
- TransferTaskMap::iterator it = transfer_tasks_.find(task_id);
- if (it==transfer_tasks_.end()) {
- if (trans_mode == IM::BaseDefine::FILE_TYPE_ONLINE) {
- transfer_task = new OnlineTransferTask(task_id, from_user_id, to_user_id, file_name, file_size);
- } else if (trans_mode == IM::BaseDefine::FILE_TYPE_OFFLINE) {
- transfer_task = new OfflineTransferTask(task_id, from_user_id, to_user_id, file_name, file_size);
- } else {
- log("Invalid trans_mode = %d", trans_mode);
- }
-
- if (transfer_task) {
- transfer_tasks_.insert(std::make_pair(task_id, transfer_task));
- }
- } else {
- log("Task existed by task_id=%s, why?????", task_id.c_str());
- }
-
- return transfer_task;
- }
這個map transfer_tasks_是在定時器裏面進行按期處理的,處理的依據是當前任務的狀態,好比已經完成的任務就能夠從map中移除了:
- void TransferTaskManager::OnTimer(uint64_t tick) {
- for (TransferTaskMap::iterator it = transfer_tasks_.begin(); it != transfer_tasks_.end();) {
- BaseTransferTask* task = it->second;
- if (task == NULL) {
- transfer_tasks_.erase(it++);
- continue;
- }
-
- if (task->state() != kTransferTaskStateWaitingUpload &&
- task->state() == kTransferTaskStateTransferDone) {
- long esp = time(NULL) - task->create_time();
- if (esp > ConfigUtil::GetInstance()->GetTaskTimeout()) {
- if (task->GetFromConn()) {
- FileClientConn* conn = reinterpret_cast<FileClientConn*>(task->GetFromConn());
- conn->ClearTransferTask();
- }
- if (task->GetToConn()) {
- FileClientConn* conn = reinterpret_cast<FileClientConn*>(task->GetToConn());
- conn->ClearTransferTask();
- }
- delete task;
- transfer_tasks_.erase(it++);
- continue;
- }
- }
-
- ++it;
- }
- }
完成這些工做之後,組裝的應答包命令號是CID_OTHER_FILE_TRANSFER_RSP,回覆給msg_server。msg_server收到該應答包後處理:
- void CFileServConn::HandlePdu(CImPdu* pPdu)
- {
- switch (pPdu->GetCommandId()) {
- ...
-
- case CID_OTHER_FILE_TRANSFER_RSP:
- _HandleFileMsgTransRsp(pPdu);
- break;
- ...
-
- }
- }
- void CFileServConn::_HandleFileMsgTransRsp(CImPdu* pPdu)
- {
- IM::Server::IMFileTransferRsp msg;
- CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()));
-
- uint32_t result = msg.result_code();
- uint32_t from_id = msg.from_user_id();
- uint32_t to_id = msg.to_user_id();
- string file_name = msg.file_name();
- uint32_t file_size = msg.file_size();
- string task_id = msg.task_id();
- uint32_t trans_mode = msg.trans_mode();
- CDbAttachData attach((uchar_t*)msg.attach_data().c_str(), msg.attach_data().length());
- log("HandleFileMsgTransRsp, result: %u, from_user_id: %u, to_user_id: %u, file_name: %s, \
- task_id: %s, trans_mode: %u. ", result, from_id, to_id,
- file_name.c_str(), task_id.c_str(), trans_mode);
-
- const list<IM::BaseDefine::IpAddr>* ip_addr_list = GetFileServerIPList();
-
- IM::File::IMFileRsp msg2;
- msg2.set_result_code(result);
- msg2.set_from_user_id(from_id);
- msg2.set_to_user_id(to_id);
- msg2.set_file_name(file_name);
- msg2.set_task_id(task_id);
- msg2.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- for (list<IM::BaseDefine::IpAddr>::const_iterator it = ip_addr_list->begin(); it != ip_addr_list->end(); it++)
- {
- IM::BaseDefine::IpAddr ip_addr_tmp = *it;
- IM::BaseDefine::IpAddr* ip_addr = msg2.add_ip_addr_list();
- ip_addr->set_ip(ip_addr_tmp.ip());
- ip_addr->set_port(ip_addr_tmp.port());
- }
- CImPdu pdu;
- pdu.SetPBMsg(&msg2);
- pdu.SetServiceId(SID_FILE);
- pdu.SetCommandId(CID_FILE_RESPONSE);
- pdu.SetSeqNum(pPdu->GetSeqNum());
- uint32_t handle = attach.GetHandle();
-
- CMsgConn* pFromConn = CImUserManager::GetInstance()->GetMsgConnByHandle(from_id, handle);
- if (pFromConn)
- {
- pFromConn->SendPdu(&pdu);
- }
-
- if (result == 0)
- {
- IM::File::IMFileNotify msg3;
- msg3.set_from_user_id(from_id);
- msg3.set_to_user_id(to_id);
- msg3.set_file_name(file_name);
- msg3.set_file_size(file_size);
- msg3.set_task_id(task_id);
- msg3.set_trans_mode((IM::BaseDefine::TransferFileType)trans_mode);
- msg3.set_offline_ready(0);
- for (list<IM::BaseDefine::IpAddr>::const_iterator it = ip_addr_list->begin(); it != ip_addr_list->end(); it++)
- {
- IM::BaseDefine::IpAddr ip_addr_tmp = *it;
- IM::BaseDefine::IpAddr* ip_addr = msg3.add_ip_addr_list();
- ip_addr->set_ip(ip_addr_tmp.ip());
- ip_addr->set_port(ip_addr_tmp.port());
- }
- CImPdu pdu2;
- pdu2.SetPBMsg(&msg3);
- pdu2.SetServiceId(SID_FILE);
- pdu2.SetCommandId(CID_FILE_NOTIFY);
-
-
- CImUser* pToUser = CImUserManager::GetInstance()->GetImUserById(to_id);
- if (pToUser)
- {
- pToUser->BroadcastPduWithOutMobile(&pdu2);
- }
-
-
- CRouteServConn* pRouteConn = get_route_serv_conn();
- if (pRouteConn) {
- pRouteConn->SendPdu(&pdu2);
- }
- }
- }
msg_server收到包後,首先裝包數據,並把file_server的ip地址和端口信息帶上,發給請求發文件的客戶端,命令號是CID_FILE_RESPONSE;接着查詢通知接收方有人給其發文件(通知方式也是同樣,若是接收方在該msg_server上,直接發給該用戶;不在的話,發給路由服務route_server)。固然接收到文件發送的端只有pc端,移動端會被過濾掉的,也就是說移動端不會收到發送文件的請求。
咱們先看發送方pc客戶端收到應答的邏輯(命令號是CID_FILE_RESPONSE):
- void FileTransferModule_Impl::onPacket(imcore::TTPBHeader& header, std::string& pbBody)
- {
- switch (header.getCommandId())
- {
- case IM::BaseDefine::FileCmdID::CID_FILE_RESPONSE:
- _sendfileResponse(pbBody);
- break;
- }
- }
- void FileTransferModule_Impl::_sendfileResponse(IN std::string& body)
- {
- IM::File::IMFileRsp imFileRsp;
- if (!imFileRsp.ParseFromString(body))
- {
- LOG__(ERR, _T("parse failed,body:%s"), util::stringToCString(body));
- return;
- }
-
- UInt32 nResult = imFileRsp.result_code();
- if (nResult != 0)
- {
- LOG__(ERR, _T("_sendfileResponse result != 0"));
- module::getFileTransferModule()->asynNotifyObserver(module::KEY_FILESEVER_UPLOAD_FAILED);
- }
-
- TransferFileEntity fileEntity;
- fileEntity.sTaskID = imFileRsp.task_id();
- assert(!fileEntity.sTaskID.empty());
- fileEntity.sFromID = util::uint32ToString(imFileRsp.from_user_id());
- fileEntity.sToID = util::uint32ToString(imFileRsp.to_user_id());
- fileEntity.sFileName = imFileRsp.file_name();
- fileEntity.setSaveFilePath(util::stringToCString(fileEntity.sFileName));
- fileEntity.time = static_cast<UInt32>(time(0));
- uint32_t transMode = imFileRsp.trans_mode();
- if (IM::BaseDefine::TransferFileType::FILE_TYPE_ONLINE == transMode)
- {
- fileEntity.nClientMode = IM::BaseDefine::ClientFileRole::CLIENT_REALTIME_SENDER;
- }
- else if (IM::BaseDefine::TransferFileType::FILE_TYPE_OFFLINE == transMode)
- {
- fileEntity.nClientMode = IM::BaseDefine::ClientFileRole::CLIENT_OFFLINE_UPLOAD;
- }
- fileEntity.pFileObject = new TransferFile(util::stringToCString(fileEntity.sFileName),FALSE);
- if (fileEntity.pFileObject)
- {
- fileEntity.nFileSize = fileEntity.pFileObject->length();
- }
-
- UINT32 nIPCount = imFileRsp.ip_addr_list_size();
- if (nIPCount <= 0)
- {
- return;
- }
- const IM::BaseDefine::IpAddr& ipAdd = imFileRsp.ip_addr_list(0);
- fileEntity.sIP = ipAdd.ip();
- fileEntity.nPort = ipAdd.port();
-
- if (!TransferFileEntityManager::getInstance()->pushTransferFileEntity(fileEntity))
- TransferFileEntityManager::getInstance()->updateFileInfoBysTaskID(fileEntity);
-
- LOG__(DEBG, _T("FileTransferSevice_Impl::準備鏈接文件服務器 sTaskId = %s"), util::stringToCString(fileEntity.sTaskID));
- TransferFileEntityManager::getInstance()->openFileSocketByTaskId(fileEntity.sTaskID);
- }
客戶端在TransferFileEntityManager::getInstance()->openFileSocketByTaskId(fileEntity.sTaskID);裏面實際去鏈接file_server並嘗試發文件:
- void TransferFileEntityManager::openFileSocketByTaskId(std::string& taskId)
- {
- m_fileUIThread->openFileSocketByTaskId(taskId);
- }
- void FileTransferUIThread::openFileSocketByTaskId(std::string& taskId)
- {
- FileTransferSocket* pFileSocket = _findFileSocketByTaskId(taskId);