UDP通信,android udp 发送接收和接收的数据里有0x00怎么办

查看: 7981|回复: 4|关注: 0
【求助】 UDP通信中如何实现数据的实时读取
<h1 style="color:# 麦片财富积分
新手, 积分 6, 距离下一级还需 44 积分
做了一个UDP通信的GUI界面,并且将发送和接收弄到了同一个界面上,在同一台电脑上试过,能够工作,点击Open Transmit UDP和Open Receive UDP之后,在左下方的白框里输入要发送的数据,点击Send Data,再点击Receive Data,可以在右下方的白框里显示接收到的数据。
但这种方式有一个问题,如果接收的是一个时间上的数据流,那么只能将点击Receive Data之前缓存接收到的数据读取出来,对点击Receive Data之后缓存接收到的数据却没法读取。要怎样解决这个问题呢。我尝试用中断回调函数,利用BytesAvailableFcn这样的方式,每接收到10个字节就读取一次缓存,但却没能成功。实在不知道该怎么办,只能求助大家了。谢谢先。
function varargout = UDPCommunication(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name',& && & mfilename, ...
& && && && && && & 'gui_Singleton',&&gui_Singleton, ...
& && && && && && & 'gui_OpeningFcn', @UDPCommunication_OpeningFcn, ...
& && && && && && & 'gui_OutputFcn',&&@UDPCommunication_OutputFcn, ...
& && && && && && & 'gui_LayoutFcn',&&[] , ...
& && && && && && & 'gui_Callback',& &[]);
if nargin && ischar(varargin{1})
& & gui_State.gui_Callback = str2func(varargin{1});
if nargout
& & [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
& & gui_mainfcn(gui_State, varargin{:});
function UDPCommunication_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hO
%=================================
%发送数据端的参数设置
ipLocal='127.0.0.1'; %本地数据端的ip,本地的
portTransmit_Local=9090; %发送数据端的端口号,本地的
ipReceive_Remote='127.0.0.1'; %接收数据端的ip和端口号,远端的
portReceive_Remote=9091;
handles.udpTransmit=udp(ipReceive_Remote,portReceive_Remote,'LocalPort',portTransmit_Local);
%接收数据端的参数设置
portReceive_Local=9091; %接收数据端的端口号,本地的
ipTransmit_Remote='127.0.0.1'; %发送数据端的ip和端口号,远端的
portTransmit_Remote=9090;
handles.udpReceive=udp(ipTransmit_Remote,portTransmit_Remote,'LocalPort',portReceive_Local);
%=================================
guidata(hObject, handles);
function varargout = UDPCommunication_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.
function pushbutton1_Callback(hObject, eventdata, handles)
%设置发送数据端缓存大小,打开发送数据端UDP
set(handles.udpTransmit,'OutputBufferSize',1024);
fopen(handles.udpTransmit);
%================================
function pushbutton2_Callback(hObject, eventdata, handles)
str=get(handles.edit1,'string');
fprintf(handles.udpTransmit,str);
%================================
function pushbutton3_Callback(hObject, eventdata, handles)
%关闭发送数据端UDP
fclose(handles.udpTransmit);
delete(handles.udpTransmit);
clear ipLocal portTransmit_Local ipReceive_Remote portReceive_Remote
%================================
function edit1_Callback(hObject, eventdata, handles)
function edit1_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
& & set(hObject,'BackgroundColor','white');
function pushbutton4_Callback(hObject, eventdata, handles)
%设置接收数据端缓存大小,打开接收数据端UDP
set(handles.udpReceive,'InputBufferSize',1024);
fopen(handles.udpReceive);
%=============================
function pushbutton5_Callback(hObject, eventdata, handles)
str=fscanf(handles.udpReceive);
set(handles.edit2,'string',str);
%=============================
function pushbutton6_Callback(hObject, eventdata, handles)
%关闭接收数据端UDP
fclose(handles.udpReceive);
delete(handles.udpReceive);
clear ipLocal portReceive_Local ipTransmit_Remote portTransmit_Remote
%=============================
function edit2_Callback(hObject, eventdata, handles)
function edit2_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
& & set(hObject,'BackgroundColor','white');
[ 本帖最后由 一枫 于
14:33 编辑 ]
<h1 style="color:# 麦片财富积分
回复 1# 一枫 的帖子
怎么有图片和附件的帖子不能发表啊,想把界面的图片、fig和m文件都贴上来,可是不行。:L :L
[localimg=383,300]1[/localimg]
[ 本帖最后由 一枫 于
14:43 编辑 ]
<h1 style="color:# 麦片财富积分
太给了了,帮我解决大问题了。狂赞啊
<h1 style="color:# 麦片财富积分
关注者: 1
学习喽 ,感谢分享!!!!!!
<h1 style="color:# 麦片财富积分
如果用UDP发送结构体,应该怎么办?
站长推荐 /2
Powered by我用socket写了一个网络通信的程序。其中涉及到这样的功能。
客户端向服务器发送一个请求,服务器端接受到这个请求后,会告诉客户下面即将发送的数据的大小。然后,服务器端就开始不停地向客户端发送数据。直到把该发送的数据发送完。然后发送一个标记,告诉客户端,数据已经发完了。
我用的tcp方式。
而客户端发送完请求后,就开始接受数据,第一个接收到的,就是服务器端发送过来的消息,告诉客户端下面即将发送过来的数据大小。然后客户端就在一个循环中接受数据,接收到来的数据会被存在内存中或者写到文件里。直到客户端收到服务器发送来的结束的标记,则停止接受数据。
我的问题是。在服务器端不停发数据的时候,客户端会出现无法完全接收数据的情况。
我试着修改每次发送数据的大小,也没有办法让客户端完整接收到数据。
我又试着让服务器每发送一次数据,就sleep一会儿,但好像也没有办法保证客户端一定能准确接收到所有数据。
后来,我在网上搜了一下,说加大客户端socket地接受缓存区大小,好像效果也不是也明显,尤其是在服务器端需要发送的数据达到好几兆时,则客户端几乎没有一次能完整接受的。
tcp数据传输,不是说是可靠传输吗?怎么服务器发送的数据,客户端就没有办法完全接受到呢。
回复讨论(解决方案)
这就是你的发送和接收的代码有问题,因为TCP/IP协议虽然是可靠传递,但是你send和recv时不一定每次都是成功发送或者接收到你设定的大小。所以在send的时候你得判断数据确实是否发送完。如如下代码:
int&nTotalSendLen&=&0;
while(nTotalSendLen&&&Length)
int&nSendLen&=&send(m_s,&buffer+nTotalSendLen,&Length-nTotalSendLen,&0);
if(nSendLen&==&SOCKET_ERROR)
int&nErrCode&=&WSAGetLastError();
if(nErrCode&==&WSAETIMEDOUT&||&nErrCode&==&WSAECONNABORTED&||&nErrCode&==&WSAEHOSTUNREACH&||&nErrCode&==&WSAESHUTDOWN)
return&0;//超时
return&-1;//错误
nTotalSendLen&+=&nSendL
接收时也同样,你得反复接收,直到你完成接收到服务通知的大小或者接收结束标志。
感谢楼上的帮助。
的代码大致如下
//MAX_SENDBUFF_LEN是定义的一次传送的数据大小,比如
#define&MAX_SENDBUFF_LEN&1024*10&//表示一次传10K
int&nSendLen&=&send(m_s,&buffer,&MAX_SENDBUFF_LEN,&0);
我在每次发送的时候,都判断返回值了
只有返回值nSendLen==MAX_SENDBUFF_LEN的时候,才认为发送成功,我看了服务器端每次调用send,返回值都是待发送字节数。这应该表示发送成功了。
在客户端,会出现以下几种情况。
第一,客户端只受到几个MAX_SENDBUFF_LEN,然后就停止那个接收函数上了(因为我用的是阻塞模式)。这就是表示客户端没有可接收的数据包了。
第二,客户端会不停地接受数据,比如服务器总共就发了1MB,但客户端确不停地接受,并且发现接收到的数据都是0x00,我为了调试,把接收到的数据保存到文件里,发现这个文件不停地增长。但用十六进制编辑器打开这个文件,发现文件后面都是0x00。
真搞不懂!
令外,如果按照楼上的发送代码,如果一直发送错误,那服务器端不就进入死循环了吗?
那么,一般情况下,控制发送多少次失败,就认为网络出问题了,不能再发了。也就是重试次数设置为多少,比较合适呢?
用非阻塞socket,并循环接收
#define&MAX_SENDBUFF_LEN&1024*10
建议LZ每次发送数据的字节数控制在1k字节以内,TCP/UDP底层包长是有限制的,具体109X还是其他,忘了
“如果按照楼上的发送代码,如果一直发送错误,那服务器端不就进入死循环了吗?”
这句说错了,楼上的代码是遇到错误,就直接退出发送。
那问题就又来了,服务器不发送了,客户端怎么办?客户端还在那里傻乎乎地等数据来呢。
因为我用的是阻塞模式。
虽然我的客户端接收数据的操作是在一个线程里,但服务器没有发送完,客户端就没有办法知道服务器端怎么了。
回4楼,虽然包长是有限制,但既然是tcp,也就是可靠传输,为什么不让我发送10K的数据,更何况,我在调用send函数发送10K的数据时候,发现返回值确实是10K,也就是说,确实发送成功了。我是在同一台机器上测试的,可以排除网络状况不好的情况。
我又做了如下试验。
让客户端每次都发送一个请求,服务器每接收到一个请求,就发送10K的数据,这样,就算服务器端发送几百MB的数据,都不会出错。
我虽然可以把程序改成这样,但还是觉得不太合适,因为还有其他的传递数据的操作不能用这用方法。
而我的客户端接收数据是在一个线程函数里实现的。
回3楼,虽然可以用非阻塞模式,但程序已经写到这份上了,如果能解决这个问题,还是不想改。不过如果实在解决不了,只能改了。
我在测试的时候,发现这样一个现象,服务器端发送数据,每次发送MAX_SENDBUFF_LEN长度的数据,总是发现服务器端很快就发完了,每次send返回值都是等于MAX_SENDBUFF_LEN,这应该说明发完。&(因为我在一台机器上测试的)。
而服务器端接收的时候,前几个包,每个包确实能接受到MAX_SENDBUFF_LEN&长的数据,并且数据也是对的。
但再往后,客户端就无法接收到数据,或则接收到的数据都是0x00。
我总觉得好像是服务器端发送的太快,客户端无法及时接收造成了。
后来,我在服务器端发送数据的时候,每发送一次,就sleep(1000),好,这回好了,可以正常接收到数据了。
可这不是解决问题的办法呀,我总不能在服务器每发送一次都sleep(1000)吧。
感觉是你程序处理的问题
不要怀疑socket,别人都用的好好的,整理一下程序处理吧,我用socket一次传10M文件都没有问题
楼主只认为服务器端有问题而忽视了客户端
这个问题显然是客户端代码有问题导致接收不完全
回10楼,我从来没有怀疑socket有问题。我只是在找问题的所在,目的是为了解决问题。
回11楼,我上午又做了大量的实验,实在无法解决问题。
我在服务器端进行了跟踪,当发送几个包后,再send确实会返回-1,也就是说发送失败了,但我用WSAGetLastError获得的错误代码竟然是0,真是郁闷。
后来,实在不行了,我使用setsockopt函数设置了一下客户端接收缓冲区的大小,我做了很多实验,发现,因为服务器端好想发送的很快,而客户端接受的确比较慢,这样一来,当客户端的接受缓冲区足够大后,发送接受数据就都没有问题了。我实验了一下,服务器发送几百MB的数据,客户端都能正常接收到。
因此,我有如下问题:
1、服务器端向客户端发送数据的时候,是不是只要客户端接受缓冲区满了,服务器端就会发送失败?
2、为什么我的客户端用recv函数接受数据这么慢呢?服务器端的数据包早就发完了,客户端还在慢慢接受数据。这是不是正常现象呢?
3、是不是正是上面说的第一个问题,才导致我现在发现的问题呢。
4、客户端在执行recv的时候,确实会将接收缓冲区里的数据清除掉所接受到的大小吗?
5、如果我在1,2,3这三个问题上的理解是正确的话,该如何处理,能很好地解决呢。
谢谢各位了,要是有好的解决办法或则思路,我会追加分数。
目前,暂时就只能用增加客户端接受缓冲区大小的方法解决我的问题了。我为了方面,直接把客户端接受缓冲区设置为4,这对系统会有什么影响吗?我在跟踪的时候,发现客户端程序并没有因为我设置这么大的缓冲区而占用系统太多内存。
又发现了问题,我在客户端请求了一个大约1G的数据,在接受到200MB的时候,又无法接受了,服务器发送又返回-1,但WSAGetLastError还是返回0,客户端接受到大约200MB后,就接受不到数据了,但客户端进程占用内存却飞速上升。最后几乎将系统拖垮!
看来,我那个设置客户端接受缓冲区大小的方法,好像并不好用!!!!!!!!!!
再次问一下,默认情况下,比如客户端在接受到10K的数据后,会不会将这个10K从接受缓冲区里移除呢?
服务器和客户端发送接收的关键代码贴出来看看
//服务器端发送数据的代码
void&DealDownLoadFile(CHostSocket&*socket,&char*&strFileName)
DownLoadFileInfo&
memset(&df,&0,&sizeof(DownLoadFileInfo));
memset(&data,&0,&sizeof(data));
data.head.cFC&=&0x0401;&//下载文件
int&nRt&=&0;
BYTE&*&buff&=&NULL;
if(f.Open(strFileName,&CFile::modeRead|CFile::typeBinary|CFile::shareDenyRead,&NULL))
//先发送文件是否存在,以及文件的长度
df.nFileLength&=&f.GetLength();
df.bExist&=&TRUE;
data.head.nlen&=&sizeof(df);
data.pszInfo&=&(BYTE*)&
nRt&=&SendPacket(socket,&&data);&//回送结果
DWORD&nCount&=&0;
buff&=&new&BYTE[MAX_REQPACK_LEN];
memset(buff,&0,&MAX_REQPACK_LEN);
nCount&=&f.ReadHuge(buff,&MAX_REQPACK_LEN);
printf(&read&%d&bytes\n&,&nCount);
if(nCount&0)
if(nCount&==&MAX_REQPACK_LEN)
data.head.cPC&=&0x0001;&//下载发送数据
data.head.cPC&=&0x0002;&//下载完成
data.head.nlen&=&nC
data.head.nSEQ&++;
data.pszInfo&=&
nRt&=&SendPacket(socket,&&data);&//发送数据
if(nRt&==&SOCKET_ERROR)
int&err&=&WSAGetLastError();
printf(&SendPacket&return&%d,&WSAGetLastError()&=&%d&\n&,&nRt,&err);
printf(&SendPacket&return&%d&\n&,&nRt);
//Sleep(100);
}while(nCount==MAX_REQPACK_LEN);
f.Close();
//清除内存
printf(&complete!\n&);
//如果打开文件失败
df.nFileLength&=&0;
df.bExist&=&FALSE;
data.head.nlen&=&sizeof(df);
data.pszInfo&=&(BYTE*)&
SendPacket(socket,&&data);&//回送结果
//客户端接受数据的代码
DWORD&CALLBACK&CNetMYS_clndlgDlg::ReceiveProc(LPVOID&lpParm)
TRACE(&线程函数已经开始&);
CNetMYS_clndlgDlg&*pDlg&=&(CNetMYS_clndlgDlg&*)lpP
CHostSocket&*pSocketPtr&=&&pDlg-&m_sC
if(NULL&==&pSocketPtr)&return&0;
while((pSocketPtr-&IsConnected())&&(INVALID_SOCKET&!=&pSocketPtr-&GetSocket())){
int&nRet&=&0;
memset(&data,&0,&sizeof(data));
nRet&=&RecvPacket(pSocketPtr,&&data);&//接收数据
if(0&&&nRet){
switch(data.head.cFC){
case&0x0001:
pDlg-&DealUserLogin(data.head.cPC);
case&0x0400:
//返回的获得目录列表
pDlg-&DealGetDirectory((PMyFileInfo)data.pszInfo);
case&0x0401:
//下载文件
//这个函数没有别的用处,无非就是将数据写到文件里罢了
pDlg-&DealDownLoadFile(&data);
case&0x0000:
//m_pClientDlg-&AcceptProc(&data);
//最后要对接收的数据进行释放
FreePacket(&data);
//Sleep(1);
TRACE(&线程函数已经结束&);
//服务器端发送数据的代码
void&DealDownLoadFile(CHostSocket&*socket,&char*&strFileName)
DownLoadFileInfo&
memset(&df,&0,&sizeof(DownLoadFileInfo));
memset(&data,&0,&sizeof(data));
data.head.cFC&=&0x0401;&//下载文件
int&nRt&=&0;
BYTE&*&buff&=&NULL;
if(f.Open(strFileName,&CFile::modeRead|CFile::typeBinary|CFile::shareDenyRead,&NULL))
//先发送文件是否存在,以及文件的长度
df.nFileLength&=&f.GetLength();
df.bExist&=&TRUE;
data.head.nlen&=&sizeof(df);
data.pszInfo&=&(BYTE*)&
nRt&=&SendPacket(socket,&&data);&//回送结果
DWORD&nCount&=&0;
buff&=&new&BYTE[MAX_REQPACK_LEN];
memset(buff,&0,&MAX_REQPACK_LEN);
nCount&=&f.ReadHuge(buff,&MAX_REQPACK_LEN);
printf(&read&%d&bytes\n&,&nCount);
if(nCount&0)
if(nCount&==&MAX_REQPACK_LEN)
data.head.cPC&=&0x0001;&//下载发送数据
data.head.cPC&=&0x0002;&//下载完成
data.head.nlen&=&nC
data.head.nSEQ&++;
data.pszInfo&=&
nRt&=&SendPacket(socket,&&data);&//发送数据
if(nRt&==&SOCKET_ERROR)
int&err&=&WSAGetLastError();
printf(&SendPacket&return&%d,&WSAGetLastError()&=&%d&\n&,&nRt,&err);
printf(&SendPacket&return&%d&\n&,&nRt);
//Sleep(100);
}while(nCount==MAX_REQPACK_LEN);
f.Close();
//清除内存
printf(&complete!\n&);
//如果打开文件失败
df.nFileLength&=&0;
df.bExist&=&FALSE;
data.head.nlen&=&sizeof(df);
data.pszInfo&=&(BYTE*)&
SendPacket(socket,&&data);&//回送结果
//客户端接受数据的代码
DWORD&CALLBACK&CNetMYS_clndlgDlg::ReceiveProc(LPVOID&lpParm)
TRACE(&线程函数已经开始&);
CNetMYS_clndlgDlg&*pDlg&=&(CNetMYS_clndlgDlg&*)lpP
CHostSocket&*pSocketPtr&=&&pDlg-&m_sC
if(NULL&==&pSocketPtr)&return&0;
while((pSocketPtr-&IsConnected())&&(INVALID_SOCKET&!=&pSocketPtr-&GetSocket())){
int&nRet&=&0;
memset(&data,&0,&sizeof(data));
nRet&=&RecvPacket(pSocketPtr,&&data);&//接收数据
if(0&&&nRet){
switch(data.head.cFC){
case&0x0001:
pDlg-&DealUserLogin(data.head.cPC);
case&0x0400:
//返回的获得目录列表
pDlg-&DealGetDirectory((PMyFileInfo)data.pszInfo);
case&0x0401:
//下载文件
//这个函数没有别的用处,无非就是将数据写到文件里罢了
pDlg-&DealDownLoadFile(&data);
case&0x0000:
//m_pClientDlg-&AcceptProc(&data);
//最后要对接收的数据进行释放
FreePacket(&data);
//Sleep(1);
TRACE(&线程函数已经结束&);
我的代码逻辑是这样的:
客户端先发送一个请求,这里测试的,就是发送一个数据头,然后发送一个文件名,数据头表示告诉服务器,我要下载文件,文件名字符串就告诉服务器端要下载的文件名称。
但实际上,我的需求不是下载文件,而是从服务器上不停地接受到数据,然后客户端进行解码并显示。
DealDownLoadFile(CHostSocket&*socket,&char*&strFileName)
这个函数,就是服务器接受到客户端的下载请求后,调用的函数,第一个参数,就是客户端的socket,第二个参数就是要下载的文件名。
客户端在发送了下载请求后,就在线程函数里,不停地接受数据。每次接受到的数据,都有一个包头,因为这个接受线程负责接受的,不仅仅是下载文件,还有其他的数据。也就是说data变量,是一个PACKET类型结构,那里定义了很多成员,其中有一个成员,就是标示接收到的数据因为什么发送过来的。
pDlg-&DealDownLoadFile(&data);
这句代码,就是先判断data的头结构成员,头结构成员里有开始,结束,等等这些标示。
再看看客户端的DealDownLoadFile函数
void&CNetMYS_clndlgDlg::DealDownLoadFile(PACKET&*data)
DownLoadFileInfo&*pdf&=&NULL;
if(data-&head.cPC==0x0000)&//表示开始发送数据
pdf&=&(DownLoadFileInfo&*)data-&pszI&
&&&&&&&&&&&&&&&&//&这个结构里,保存了要下载文件的大小,crc32等文件信息
if(!pdf-&bExist)
m_listBoxMsg.AddString(&下载失败,服务器端无法打开文件!&);
CString&s;
s.Format(&开始下载文件,文件长度=%d&,&pdf-&nFileLength);
m_listBoxMsg.AddString(s);
DeleteFile(&C:\\ext-2.0.zip&);&//如果文件存在就删除
else&//这才是表示正式发送的数据
f.Open(&C:\\ext-2.0.zip&,&CFile::modeWrite|CFile::modeCreate|CFile::modeNoTruncate,&NULL);
f.SeekToEnd();
f.WriteHuge(data-&pszInfo,&data-&head.nlen);
f.Close();
if(data-&head.cPC==0x0002)
m_listBoxMsg.AddString(&文件下载完成&);
其实,这个函数,我是为了模拟解码,显示的过程,为了测试,我就把获得数据写到文件里了。
事实上,一旦客户端请求发送数据后,服务器要发送的数据可能会很多,如果要写到文件里的话,可能会上GB甚至更多。客户端其实不需要保存到文件里,客户端接受到数据后,进行解码,然后显示出来,就算完成任务了。
另外RecvPacket和SendPacket使自己封装的发送和接收函数,没有什么特别的,就是调用了recv和send函数。
因为收到的数据是保存在一个结构里,结构的最后一个成员是一个BYTE*,这个指针是动态分配的,所以,要调用FreePacket释放,这个FreePacket也使自己封装的。
数据量大的时候是很麻烦啊,关注中……
昨晚搞了很晚,将发送接受模式改成一问一答的形式。
也就是客户端发送请求数据的请求,服务器端收到后,就发送一块数据。
这样一问一答的形式,倒是解决了我的问题。包括每次send的数据10K,客户端都能正确接受。我把程序改成一问一答的形式后做了大数据量测试,连续运行了一夜,传递的数据大约已经有上百GB了,系统还算稳定,内存使用也没有增加。
但有一点不是很爽,好像这种一问一答的方式并没有充分利用网络带宽,所以,网络传送速度并不是很理想。
有待于一步优化了。
各位有没有更好的解决方法?劳驾指导一下!新版 ChinaUnix 客户端强势归来!
扫描二维码安装
扫描二维码安装
支持分类信息/主题分类
支持搜索/分享/删选/注册
社区新帖热帖实时更新
所有数据和网站实时同步
查看周边用户、周边帖子
查看网友发帖位置
随时随地拍照上传
可多选5张照片
轻松录音上传
倾听ta的声音
回复信息及时通知
和好友实时语音交流
北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处}

我要回帖

更多关于 stm32 udp 接收发送 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信