网络传送bmp格式图片?
各位大侠,我自己写的服务端和客户端,客户端请求服务端发送指定的文件,服务端接收请求将图片发送过去;现在问题出来了:
第一个问题,客户端接收的数据与服务端发送的数据有时会出现不一致,以至于图片显示错误;
第二个问题,如果我服务端设置套接字为非阻塞模式时,服务端有时会出现发送数据不完整的错误;
所以我想请教大侠,如何才能避免这些问题,谢谢!
[解决办法]
1. TCP,或者UDP+校验
2. 设置包头,指定大小,序号等,重发机制
[解决办法]
第一个问题,服务器发一包数据,客户端回一包数据应答,服务器收到应答消息再发送下一包
第二个问题,发送数据,不用设置套接字为非阻塞模式,这样你就可以检查send的返回值看看数据是否完整发送了
[解决办法]
长度+数据,自定义应用层协议
[解决办法]
/*****************************************************************************\ * hSocket: 套接字句柄 * fName: 发送的本地文件路径\*****************************************************************************/BOOL SendFile(SOCKET hSocket, CString fName){ BOOL bRet = TRUE; int fileLength, cbLeftToSend; // pointer to buffer for sending data (memory is allocated after sending file size) BYTE* sendData = NULL; CFile sourceFile; CFileException fe; BOOL bFileIsOpen = FALSE; if( !( bFileIsOpen = sourceFile.Open( fName, CFile::modeRead | CFile::typeBinary, &fe ) ) ) { TCHAR strCause[256]; fe.GetErrorMessage( strCause, 255 ); TRACE( "SendFileToRemoteRecipient encountered an error while opening the local file\n" "\tFile name = %s\n\tCause = %s\n\tm_cause = %d\n\tm_IOsError = %d\n", fe.m_strFileName, strCause, fe.m_cause, fe.m_lOsError ); /* you should handle the error here */ bRet = FALSE; goto PreReturnCleanup; } // first send length of file fileLength = sourceFile.GetLength(); fileLength = htonl( fileLength ); cbLeftToSend = sizeof( fileLength ); do { int cbBytesSent; const char* bp = (const char*)(&fileLength) + sizeof(fileLength) - cbLeftToSend; cbBytesSent = send(hSocket, bp, cbLeftToSend, 0); // test for errors and get out if they occurred if ( cbBytesSent == SOCKET_ERROR ) { int iErr = ::GetLastError(); TRACE( "SendFileToRemoteRecipient returned a socket error while sending file length\n" "\tNumber of Bytes sent = %d\n" "\tGetLastError = %d\n", cbBytesSent, iErr ); /* you should handle the error here */ bRet = FALSE; goto PreReturnCleanup; } // data was successfully sent, so account for it with already-sent data cbLeftToSend -= cbBytesSent; } while ( cbLeftToSend > 0 ); // now send the file's data sendData = new BYTE[SEND_BUFFER_SIZE]; cbLeftToSend = sourceFile.GetLength(); do { // read next chunk of SEND_BUFFER_SIZE bytes from file int sendThisTime, doneSoFar, buffOffset; sendThisTime = sourceFile.Read( sendData, SEND_BUFFER_SIZE ); buffOffset = 0; do { doneSoFar = send(hSocket, (const char*)(sendData + buffOffset), sendThisTime, 0); // test for errors and get out if they occurred if ( doneSoFar == SOCKET_ERROR ) { int iErr = ::GetLastError(); TRACE( "SendFileToRemoteRecipient returned a socket error while sending chunked file data\n" "\tNumber of Bytes sent = %d\n" "\tGetLastError = %d\n", doneSoFar, iErr ); /* you should handle the error here */ bRet = FALSE; goto PreReturnCleanup; } /*************************** un-comment this code and put a breakpoint here to prove to yourself that sockets can send fewer bytes than requested if ( doneSoFar != sendThisTime ) { int ii = 0; }****************************/ // data was successfully sent, so account for it with already-sent data buffOffset += doneSoFar; sendThisTime -= doneSoFar; cbLeftToSend -= doneSoFar; } while ( sendThisTime > 0 ); } while ( cbLeftToSend > 0 ); PreReturnCleanup: // labelled goto destination // free allocated memory // if we got here from a goto that skipped allocation, delete of NULL pointer // is permissible under C++ standard and is harmless delete[] sendData; if ( bFileIsOpen ) sourceFile.Close(); // only close file if it's open (open might have failed above) return bRet;}/*****************************************************************************\ * hSocket: 套接字句柄 * fName: 要接收到本地的文件路径\*****************************************************************************/BOOL RecvFile(SOCKET hSocket, CString fName){ BOOL bRet = TRUE; // return value int dataLength, cbBytesRet, cbLeftToReceive; // used to monitor the progress of a receive operation BYTE* recdData = NULL; // pointer to buffer for receiving data (memory is allocated after obtaining file size) CFile destFile; CFileException fe; BOOL bFileIsOpen = FALSE; // open/create target file that receives the transferred data if( !( bFileIsOpen = destFile.Open( fName, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary, &fe ) ) ) { TCHAR strCause[256]; fe.GetErrorMessage( strCause, 255 ); AfxMessageBox(fName); CString strErrMsg; strErrMsg.Format("GetFileFromRemoteSender encountered an error while opening the local file\n" "\tFile name = %s\n\tCause = %s\n\tm_cause = %d\n\tm_IOsError = %d\n", fe.m_strFileName, strCause, fe.m_cause, fe.m_lOsError); AfxMessageBox( strErrMsg ); /* you should handle the error here */ bRet = FALSE; goto PreReturnCleanup; } // get the file's size first cbLeftToReceive = sizeof( dataLength ); do { char* bp = (char*)(&dataLength) + sizeof(dataLength) - cbLeftToReceive; cbBytesRet = recv(hSocket, bp, cbLeftToReceive, 0); // test for errors and get out if they occurred if ( cbBytesRet == SOCKET_ERROR || cbBytesRet == 0 ) { int iErr = ::GetLastError(); CString strErr; strErr.Format("GetFileFromRemoteSite returned a socket error while getting file length\n" "\tNumber of Bytes received (zero means connection was closed) = %d\n" "\tGetLastError = %d\n", cbBytesRet, iErr ); /* you should handle the error here */ AfxMessageBox(strErr); bRet = FALSE; goto PreReturnCleanup; } // good data was retrieved, so accumulate it with already-received data cbLeftToReceive -= cbBytesRet; } while ( cbLeftToReceive > 0 ); dataLength = ntohl( dataLength ); // now get the file in RECV_BUFFER_SIZE chunks at a time recdData = new byte[RECV_BUFFER_SIZE]; cbLeftToReceive = dataLength; do { int iiGet, iiRecd; iiGet = (cbLeftToReceive<RECV_BUFFER_SIZE) ? cbLeftToReceive : RECV_BUFFER_SIZE ; iiRecd = recv(hSocket, (char *)recdData, iiGet, 0); // test for errors and get out if they occurred if ( iiRecd == SOCKET_ERROR || iiRecd == 0 ) { int iErr = ::GetLastError(); TRACE( "GetFileFromRemoteSite returned a socket error while getting chunked file data\n" "\tNumber of Bytes received (zero means connection was closed) = %d\n" "\tGetLastError = %d\n", iiRecd, iErr ); /* you should handle the error here */ bRet = FALSE; goto PreReturnCleanup; }/************************* un-comment this code and put a breakpoint here to prove to yourself that sockets can return fewer bytes than requested if ( iiGet != iiRecd ) { int ii=0; } ***************************/ // good data was retrieved, so accumulate it with already-received data destFile.Write( recdData, iiRecd); // Write it cbLeftToReceive -= iiRecd; } while ( cbLeftToReceive > 0 ); PreReturnCleanup: // labelled "goto" destination // free allocated memory // if we got here from a goto that skipped allocation, delete of NULL pointer // is permissible under C++ standard and is harmless delete[] recdData; if ( bFileIsOpen ) destFile.Close(); // only close file if it's open (open might have failed above) return bRet;}
[解决办法]
这样的问题都是需要通过制定通信协议来解决的
每个数据包携带固定的数据
具有自己的意义
接收端按包解析出来即可
根据包头信息进行断包