TCP发送文件(转)
//文件传送线程//服务器发送文件,客户端发送文件消息 UINT threadSendFile(LPVOID pvar) { CDlgSendMessage *pDlg = (CDlgSendMessage *) pvar; CFile m_fSendfile; m_fSendfile.Close(); if (!m_fSendfile.Open(pDlg->m_sendfilepath, CFile::modeRead | CFile::typeBinary)) { AfxMessageBox("打开文件失败!"); return false; } SOCKET sSendMsg;//客户端套接字 SOCKADDR_IN inetAddr; sSendMsg = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (INVALID_SOCKET == sSendMsg) { AfxMessageBox( "创建客户端发送套接字失败!"); m_fSendfile.Close(); return 0; } inetAddr.sin_family = AF_INET; inetAddr.sin_port = htons(PUB_MSG_PORT); inetAddr.sin_addr.s_addr= inet_addr(pDlg->m_receiveip);//为接受文件者IP if (SOCKET_ERROR == connect(sSendMsg, (SOCKADDR *)&inetAddr, sizeof(SOCKADDR_IN)))//为接受文件者 { AfxMessageBox("对方不在线,不存在监听套接字失败!"); closesocket(sSendMsg); m_fSendfile.Close(); return 0; } char buff[MAX_BUF_SIZE] = ""; CString strMsgSend("1001/"); CString strSize; //计算文件大小 if (pDlg->m_fiSendFile.nFileSizeLow / (1024 * 1024) != 0) { strSize.Format("%.2fMB", pDlg->m_fiSendFile.nFileSizeLow / (1024.0 * 1024)); } else { strSize.Format("%.2fKB", pDlg->m_fiSendFile.nFileSizeLow / (1024.0)); } memcpy(buff, pDlg->m_fiSendFile.szFileTitle, sizeof(pDlg->m_fiSendFile.szFileTitle)); strMsgSend += buff; strMsgSend += "/"; strMsgSend += strSize; strMsgSend += "/"; //发送文件标题,文件大小//作为客户端发消息和接受套接字 if (SOCKET_ERROR == send(sSendMsg, strMsgSend.GetBuffer(0), strMsgSend.GetLength(), 0)) { AfxMessageBox( "发送消息失败!: threadSendFile"); closesocket(sSendMsg); m_fSendfile.Close(); return 0; } memset(buff, 0, MAX_BUF_SIZE); if (SOCKET_ERROR == recv(sSendMsg, buff, MAX_BUF_SIZE, 0))//收到对方反馈信息//收到同意接受信息 { AfxMessageBox( "接收消息失败!: threadSendFile"); closesocket(sSendMsg); m_fSendfile.Close(); return 0; } //解析对方的确认信息 CString strCmd; strCmd += buff; strCmd = strCmd.Left(4); int iCmd = -1; iCmd = atoi(strCmd); if (MSG_ACCEPT != iCmd) { AfxMessageBox( "对方拒绝接收文件!: threadSendFile"); closesocket(sSendMsg); m_fSendfile.Close(); return false;// } //对方同意接收文件,开始发送 //创建服务器 发送文件socket, 打开FILE_PORT SOCKET sSendFile;//监听套接字 SOCKET sAccept;//发送接受套接字 SOCKADDR_IN inetAddrSendFile; SOCKADDR_IN inetAddrAccept; sSendFile = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (INVALID_SOCKET == sSendFile) { AfxMessageBox( "创建套接字错误!: threadSendFile"); closesocket(sSendMsg); m_fSendfile.Close(); return 0; } inetAddrSendFile.sin_addr.s_addr = htonl(INADDR_ANY); inetAddrSendFile.sin_port = htons(PUB_FILE_PORT); inetAddrSendFile.sin_family = AF_INET; if (SOCKET_ERROR == bind(sSendFile, (SOCKADDR *)&inetAddrSendFile, sizeof(SOCKADDR))) { AfxMessageBox( "绑定套接字错误!: threadSendFile"); closesocket(sSendMsg); closesocket(sSendFile); m_fSendfile.Close(); return 0; } if (SOCKET_ERROR == listen(sSendFile, 5)) { AfxMessageBox( "监听错误!: threadSendFile"); closesocket(sSendMsg); closesocket(sSendFile); m_fSendfile.Close(); return 0; } int iLen = sizeof(SOCKADDR); sAccept = accept(sSendFile, (SOCKADDR *)&inetAddrAccept, &iLen); if (INVALID_SOCKET == sAccept) { AfxMessageBox( "accept socket error occurred!: threadSendFile"); closesocket(sSendMsg); closesocket(sSendFile); m_fSendfile.Close(); return 0; } //发送文件信息给对方 char buffInfo[MAX_BUF_SIZE] = ""; memcpy(buffInfo, &pDlg->m_fiSendFile, sizeof(pDlg->m_fiSendFile)); send(sAccept, buffInfo, sizeof(pDlg->m_fiSendFile), 0); memset(buffInfo, 0, MAX_BUF_SIZE); //对方同意接收huozebujieshou,开始传送 recv(sAccept, buffInfo, MAX_BUF_SIZE, 0);//对方不保持就不往下走 //循环发送文件 DWORD dwRead = 0; DWORD dwCurrentRead = 0; BYTE *bReadBuff = new BYTE[MAX_BUF_SIZE]; //设置发送进度 while (dwRead < pDlg->m_fiSendFile.nFileSizeLow) { dwCurrentRead = 0; memset(bReadBuff, 0, MAX_BUF_SIZE); dwCurrentRead = m_fSendfile.Read(bReadBuff, MAX_BUF_SIZE);//读数据到缓冲区 if (SOCKET_ERROR == send(sAccept, (char *)bReadBuff, dwCurrentRead, 0))//发送数据 { AfxMessageBox( "文件发送中断!: threadSendFile");//如果对方取消持,发送方也也一直往下走 closesocket(sSendMsg); closesocket(sSendFile); m_fSendfile.Close(); break; } dwRead += dwCurrentRead;//已经发送数据 CString str; str.Format("%d", dwRead); AfxMessageBox("已经发送"+str); } AfxMessageBox("发送完成"); delete bReadBuff; //释放堆内存 //结束时处理 m_fSendfile.Close();//文件关闭 if (INVALID_SOCKET != sAccept) { closesocket(sAccept);//关闭接受套接字 } if (INVALID_SOCKET != sSendFile) { closesocket(sSendFile);//关闭发送套接字 } AfxEndThread(0); return 1; } //客户端文件接收线程 UINT threadRecvFile(LPVOID pvar) { char * m_sip=(char *)pvar; SOCKET sFileRecv; SOCKADDR_IN inetAddr; //新建一个客户socket,连接文件 发送方服务器 接收文件 sFileRecv = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (INVALID_SOCKET == sFileRecv) { AfxMessageBox( "创建套接字失败 : threadRecvFile"); AfxEndThread(0); return 0; } inetAddr.sin_family = AF_INET; inetAddr.sin_port = htons(PUB_FILE_PORT); inetAddr.sin_addr.s_addr = inet_addr(m_sip); if (SOCKET_ERROR == connect(sFileRecv, (SOCKADDR *)&inetAddr, sizeof(SOCKADDR)))//连接服务器IP { AfxMessageBox("连接对方主机错误 : threadRecvFile"); closesocket(sFileRecv); AfxEndThread(0); return 0; } //接收文件信息 FileInfo fiRecvFile; if (SOCKET_ERROR == recv(sFileRecv, (char *)&fiRecvFile, sizeof(FileInfo), 0)) { AfxMessageBox("接收文件信息错误 : threadRecvFile"); closesocket(sFileRecv); AfxEndThread(0); return 0; } CString strFileInfo; double nfileSize = 0.0; if (fiRecvFile.nFileSizeLow / (1024 * 1024) != 0) { nfileSize = fiRecvFile.nFileSizeLow / (1024 * 1024); strFileInfo.Format("正在接收文件...\n 来自[%s], \n文件名[%s] 大小:[%.2f]MB", inet_ntoa(inetAddr.sin_addr), fiRecvFile.szFileTitle, nfileSize); } else { nfileSize = fiRecvFile.nFileSizeLow / (1024); strFileInfo.Format("正在接收文件...\n 来自[%s], \n文件名[%s] 大小:[%.2f]KB", inet_ntoa(inetAddr.sin_addr), fiRecvFile.szFileTitle, nfileSize); } CFileDialog fdlgSave( FALSE,NULL,fiRecvFile.szFileTitle, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, _T("所有 (*.*)|*.*|")); char buff[MAX_BUF_SIZE] = ""; CAcModuleResourceOverride thisResource; if (fdlgSave.DoModal() != IDOK) { sprintf(buff, "%d", MSG_REJECT); send(sFileRecv, buff, sizeof(buff), 0); closesocket(sFileRecv);//导致发送文件中端 AfxEndThread(0); } CString strFilePath; strFilePath = fdlgSave.GetPathName(); CFile fRecvedFile(strFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary); DWORD dwTotalRead; DWORD dwCurrentRead; dwTotalRead = 0; //接收总字节 dwCurrentRead = 0; //此次接收字节 BYTE *dataBuff = new BYTE[MAX_BUF_SIZE]; //分配堆内存缓冲 //开始接收 memset(buff, 0, sizeof(buff)); sprintf(buff, "%d", MSG_BEGIN); send(sFileRecv, buff, sizeof(buff), 0); while (dwTotalRead < fiRecvFile.nFileSizeLow) { dwCurrentRead = 0; memset(dataBuff, 0, MAX_BUF_SIZE); dwCurrentRead = recv(sFileRecv, (char *)dataBuff, MAX_BUF_SIZE, 0); if (0 == dwCurrentRead || SOCKET_ERROR == dwCurrentRead) { CString strFileRecvInfo; strFileRecvInfo.Format("接收:%s失败!", fiRecvFile.szFileTitle); break; } fRecvedFile.Write(dataBuff, dwCurrentRead); dwTotalRead += dwCurrentRead; // CString str; // str.Format("%d",dwTotalRead); // AfxMessageBox("已经接受"+str); double iCompleted = 0.0; iCompleted = (dwTotalRead * 1.0) / fiRecvFile.nFileSizeLow; iCompleted *= 10.0; CString strSavedInfo; strSavedInfo.Format("%d", iCompleted); } delete dataBuff; //释放堆内存 CString strFileRecvInfo; strFileRecvInfo.Format("接收:%s完成!", fiRecvFile.szFileTitle); AfxMessageBox(strFileRecvInfo); if (sFileRecv != INVALID_SOCKET) { closesocket(sFileRecv); } //关闭文件 fRecvedFile.Close(); //清空文件信息 // memset(&pDlg->m_fiSendFile, 0, sizeof(pDlg->m_fiSendFile)); // AfxEndThread(0); return 1; } //服务监听线程//建立服务器模型 UINT threadServer(LPVOID pvar) { SOCKADDR_IN inetAddr; SOCKADDR_IN inetAccept; SOCKET sAccept; SOCKET MySock; //服务器监听套接字MYSOCK; MySock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (INVALID_SOCKET == MySock) { AfxMessageBox( "套接字创建失败!"); return FALSE; } inetAddr.sin_family = AF_INET; inetAddr.sin_port = htons(PUB_MSG_PORT); //消息监听端口 //inetAddr.sin_port = 0; inetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //绑定 if (INVALID_SOCKET == bind(MySock, (SOCKADDR *)&inetAddr, sizeof(SOCKADDR))) { AfxMessageBox( "套接字绑定错误 : threadServer!"); closesocket(MySock); return 0; } //监听 if (0 != listen(MySock, 5)) { AfxMessageBox("套接字监听错误 : threadServer!"); return 0; } // AfxMessageBox("消息服务启动成功"); //accept int ilen = sizeof(SOCKADDR_IN); while(TRUE) {//服务器会话套接字 sAccept = accept(MySock, (SOCKADDR *)&inetAccept, &ilen); if (INVALID_SOCKET == sAccept) { AfxMessageBox("接受套接字失败 : threadServer!"); return 0; } //启动消息处理线程处理新到达的消息 //分配堆内存,存放客户socket信息 SocketInfo *psInfo = new SocketInfo; memset(psInfo, 0, sizeof(SocketInfo)); psInfo->sNow = sAccept; psInfo->inetAddr = inetAccept;//客户机的地址 AfxBeginThread(threadRecvMsg, (LPVOID)psInfo); }//while return 1; } //服务器处理 消息处理线程,新消息到达后启动,处理完毕关闭 UINT threadRecvMsg(LPVOID pvar) { SocketInfo *psockInfo = (SocketInfo *)pvar; SocketInfo sockInfo = *psockInfo; delete psockInfo; //释放堆内存 //每个线程里都有单独的内存,必须释放才能引用,实际上是子线程偷了父线程的内存 int iRecv = -1; char buff[MAX_BUF_SIZE] = ""; char szMsg[256] = ""; //开始接收消息 iRecv = recv(sockInfo.sNow, buff, sizeof(buff), 0);// if (SOCKET_ERROR == iRecv) { closesocket(sockInfo.sNow); AfxMessageBox( "接收消息出错!: threadRecvMsg"); AfxEndThread(0); } //1001/暴风影音2007.exe/32MB/ strcpy(szMsg, buff); int itype = 0; CString strTemp; CString strInMsg; strTemp += szMsg; strInMsg += szMsg; strTemp = strTemp.Left(4); itype = atoi(strTemp); //判断是否为文件到达消息 if (MSG_NEW_FILE == itype) { CString strMsgInfo; CString strHost; CString strFileName; CString strSize; int i, j; i = 0; j = 0; i = strInMsg.Find("/"); j = strInMsg.Find("/", i + 1); //取得文件名称 strFileName = strInMsg.Mid(i + 1, j - i - 1); strInMsg.TrimRight("/"); //取得文件大小 strSize = strInMsg.Right(strInMsg.GetLength() - strInMsg.ReverseFind('/') - 1); strMsgInfo.Format("[文件来源:%s]\n[文件名称:%s]\n[文件大小:%s]", inet_ntoa(sockInfo.inetAddr.sin_addr), strFileName, strSize); strMsgInfo += "\n同意接收吗?"; CAcModuleResourceOverride thisResource; if (IDYES == MessageBox(NULL, strMsgInfo, "新消息", MB_YESNO)) { char buffSend[MAX_BUF_SIZE] = ""; char sztemp[20] = ""; itoa(MSG_ACCEPT, sztemp, 10); strcpy(buffSend, sztemp); //发送同意接收消息给对方 if (SOCKET_ERROR == send(sockInfo.sNow, buffSend, sizeof(buffSend), 0)) { AfxMessageBox( "发送消息失败 : threadRecvMsg"); closesocket(sockInfo.sNow); AfxEndThread(0); }//if char * senderip; senderip=inet_ntoa(sockInfo.inetAddr.sin_addr); //启动文件接收线程 AfxBeginThread(threadRecvFile, (LPVOID)senderip); }//if else { char buffSend[MAX_BUF_SIZE] = ""; char sztemp[20] = ""; itoa(MSG_REJECT, sztemp, 10); strcpy(buffSend, sztemp); //发送拒绝接收消息给对方 if (SOCKET_ERROR == send(sockInfo.sNow, buffSend, sizeof(buffSend), 0)) { AfxMessageBox( "发送消息失败 : threadRecvMsg"); closesocket(sockInfo.sNow); AfxEndThread(0); }//if }//else }//if else { AfxMessageBox("无法识别的消息"); }//else return 0; }