网络传送bmp格式图片?

thegreatone 2012-01-05 02:52:57
各位大侠,我自己写的服务端和客户端,客户端请求服务端发送指定的文件,服务端接收请求将图片发送过去;现在问题出来了:
第一个问题,客户端接收的数据与服务端发送的数据有时会出现不一致,以至于图片显示错误;
第二个问题,如果我服务端设置套接字为非阻塞模式时,服务端有时会出现发送数据不完整的错误;
所以我想请教大侠,如何才能避免这些问题,谢谢!
...全文
298 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
辰岡墨竹 2012-01-10
  • 打赏
  • 举报
回复
你要自己定义个通信协议,发图片时指定尺寸、大小、色深什么的。然后发送完毕要有一个校验字(可以是CRC之类的)以及结束符。
如果错误就要求重发。
另外直接发BMP不太好,单线程又没有额外控制,这么大的失败率比较高。建议先压缩成png、jpg之类的再发送。
如果是连续的截图的话,可以考虑差分压缩,只传送图片改变的部分。
向立天 2012-01-10
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 thegreatone 的回复:]

目前,我的问题是不能完整接收数据包!
[/Quote]
你前面说了你的问题是粘包
所以需要定义包头包尾做区分
如果黏在一起了就按协议分开
如果没有接收完整就继续介绍
如果接收不到完整的包证明通信出错可以申请重发
以上都是通信协议应有的问题
你一味的强调“问题是不能完整接收数据包!”
用再多“!”号也只能说明你不是十分明白什么是通信协议
thegreatone 2012-01-10
  • 打赏
  • 举报
回复
目前,我的问题是不能完整接收数据包!
向立天 2012-01-10
  • 打赏
  • 举报
回复
这样的问题都是需要通过制定通信协议来解决的
每个数据包携带固定的数据
具有自己的意义
接收端按包解析出来即可
根据包头信息进行断包
King_hhuang 2012-01-10
  • 打赏
  • 举报
回复
什么也不说了,直接上代码,自己研究一下吧

/*****************************************************************************\
* 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;


}
morrist1987 2012-01-10
  • 打赏
  • 举报
回复
怎么到处都是兔子党的啊?兔子党是个啥组织。求偷窥
UDX协议 2012-01-10
  • 打赏
  • 举报
回复
UDP传这些,比较麻烦,需要采用可靠UDP协议。
蒙飞鸿 2012-01-05
  • 打赏
  • 举报
回复
send /recv 的返回值判断一下就好了
laolei 2012-01-05
  • 打赏
  • 举报
回复
在包头的时候自定义一个结构体:包括图片大小等,数据包的个数等信息。每次发包时加一个序号。每次传送文件这么做肯定没有问题。
thegreatone 2012-01-05
  • 打赏
  • 举报
回复
我查了一下应该是粘包吧!但是为什么会读的数据会比发送的数据少呢?
thegreatone 2012-01-05
  • 打赏
  • 举报
回复
tcp协议
shn521 2012-01-05
  • 打赏
  • 举报
回复
你用的是udp协议吧
jsyren 2012-01-05
  • 打赏
  • 举报
回复
贴上具体代码吧,不然问题不清啊
thegreatone 2012-01-05
  • 打赏
  • 举报
回复
如果出现读数据不对的情况,是不是可以清除缓冲区。
thegreatone 2012-01-05
  • 打赏
  • 举报
回复
大家好,现在一个重要的原因是为什么会出现数据没有读完就不读的现象!
oyljerry 2012-01-05
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 thegreatone 的回复:]
可是会出现这样的情况,如果客户端第一次没有接收服务端发送的所有的信息的话,那么在下一次接收时会出现比服务端所发送数据较多的数据量。这种请问这咱情况该如何解决!
[/Quote]
定义包头等指定数据大小,长度等
thegreatone 2012-01-05
  • 打赏
  • 举报
回复
可是会出现这样的情况,如果客户端第一次没有接收服务端发送的所有的信息的话,那么在下一次接收时会出现比服务端所发送数据较多的数据量。这种请问这咱情况该如何解决!
Eleven 2012-01-05
  • 打赏
  • 举报
回复
长度+数据,自定义应用层协议
fishion 2012-01-05
  • 打赏
  • 举报
回复
第一个问题,服务器发一包数据,客户端回一包数据应答,服务器收到应答消息再发送下一包
第二个问题,发送数据,不用设置套接字为非阻塞模式,这样你就可以检查send的返回值看看数据是否完整发送了
oyljerry 2012-01-05
  • 打赏
  • 举报
回复
1. TCP,或者UDP+校验
2. 设置包头,指定大小,序号等,重发机制

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧