读书人

网络传送bmp格式图片?该怎么解决

发布时间: 2012-03-11 18:15:38 作者: rapoo

网络传送bmp格式图片?
各位大侠,我自己写的服务端和客户端,客户端请求服务端发送指定的文件,服务端接收请求将图片发送过去;现在问题出来了:
第一个问题,客户端接收的数据与服务端发送的数据有时会出现不一致,以至于图片显示错误;
第二个问题,如果我服务端设置套接字为非阻塞模式时,服务端有时会出现发送数据不完整的错误;
所以我想请教大侠,如何才能避免这些问题,谢谢!

[解决办法]
1. TCP,或者UDP+校验
2. 设置包头,指定大小,序号等,重发机制
[解决办法]
第一个问题,服务器发一包数据,客户端回一包数据应答,服务器收到应答消息再发送下一包
第二个问题,发送数据,不用设置套接字为非阻塞模式,这样你就可以检查send的返回值看看数据是否完整发送了
[解决办法]
长度+数据,自定义应用层协议
[解决办法]

探讨
可是会出现这样的情况,如果客户端第一次没有接收服务端发送的所有的信息的话,那么在下一次接收时会出现比服务端所发送数据较多的数据量。这种请问这咱情况该如何解决!

[解决办法]
在包头的时候自定义一个结构体:包括图片大小等,数据包的个数等信息。每次发包时加一个序号。每次传送文件这么做肯定没有问题。
[解决办法]
send /recv 的返回值判断一下就好了
[解决办法]
什么也不说了,直接上代码,自己研究一下吧
C/C++ code
/*****************************************************************************\ * 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;} 


[解决办法]
这样的问题都是需要通过制定通信协议来解决的
每个数据包携带固定的数据
具有自己的意义
接收端按包解析出来即可
根据包头信息进行断包

读书人网 >VC/MFC

热点推荐