C++ Builder下三种UDP通信实现方法的比较[转]
来源:互联网 发布:淘宝客软件定制 编辑:程序博客网 时间:2024/05/18 23:27
关键字 C++ Builder下三种UDP通信实现方法的比较
出处
主要讨论一下数据的接受:
1.NMUDP控件
这个控件使用起来比较简单,设定监听端口,然后响应DataReceived事件就可以了,例如:
void __fastcall TMoniter::NMUDPDataReceived(TComponent *Sender,
int NumberBytes, AnsiString FromIP, int Port)
{
/* 用一个标志变量控制控件受信后是否执行需要的操作 */
if (recvFlag)
{
int rl;
/* 用于接受数据的内存 */
unsigned char rbuf[1024 * 9];
/* 控件的ReadBuffer方法,把接受到的数据存储到rbuf */
NMUDP -> ReadBuffer(rbuf , sizeof(rbuf) , rl);
/* 字符串结束 */
rbuf[rl]=0;
/* stream是事先定义的文件指针 */
if (stream != NULL)
{
/* 自编doLog函数,把接收数据写入日志文件 */
doLog( false , rbuf ,rl ;
}
}
}
这个控件的优点是使用简单、效率比较高,但是只支持2K的缓冲,所以上面开辟的9K内存是多余的。2K的限制使我在项目中不得不放弃了这个控件。
2.IdUDPServer控件
使用方法跟NMUDP差不多,响应UDPRead事件就可以了,例如:(注释参考1)
void __fastcall TMoniter::IdUDPServer1UDPRead(TObject *Sender,
TStream *AData, TIdSocketHandle *ABinding)
{
if (recvFlag)
{
int r1;
unsigned char rbuf[1024 * 9];
r1 = AData->Size;
/* 接受到的数据是存放在数据流AData中的,把它们读到rbuf里去 */
AData->Read(rbuf , r1);
rbuf[r1] = 0;
if (stream != NULL)
{
doLog( false , rbuf ,r1);
}
}
}
这个控件支持了9K的缓冲,但是效率……我需要1秒钟接收150个1K多的数据包并解码后逐行显示在StringGrid中,虽然主要是对StringGrid的描绘浪费时间,但IdUDPServer还是不能令人满意。
3.回归自然吧——Socket
两个控件都不能满足我的需要,那么只能回头考虑底层的socket(我的C不好,对这个方法现在还不是很明白,所以注释很少,不过通过代码能大约猜出其功能)。
先定义这三个东东:
SOCKET sock
WSADATA wsaData
SOCKADDR_IN sockaddr
然后在需要开始受信的地方进行socket初始化,这里我用了一个按钮:
int result;
WORD wVersionRequested;
wVersionRequested = MAKEWORD(1,1);
if((result = WSAStartup(wVersionRequested,&wsaData))!=0)
{
Application->MessageBoxA("Socket Initial Error","Error",MB_OK);
WSACleanup();
return;
}
memset(&sockaddr,0,sizeof(sockaddr));
/* 设置端口号 */
sockaddr.sin_port=htons(3000);
sockaddr.sin_family=AF_INET;
sockaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock == INVALID_SOCKET)
{
Application->MessageBoxA("Socket Open failed","Error",MB_OK);
WSACleanup();
return;
}
result = bind(sock,(LPSOCKADDR)&sockaddr,sizeof sockaddr);
if(result == SOCKET_ERROR)
{
Application->MessageBoxA("Bind Error","Error",MB_OK);
WSACleanup();
return;
}
/* 自写函数getFileReady打开一个日志文件等待记录数据 */
if( !getFileReady()
{
WSACleanup();
return;
}
/* 把StringGrid编辑区域清理一下 */
sgLog -> RowCount = 2;
sgLog -> Rows[1] -> Clear();
sgLog -> Cells[0][1] = "1";
lineCount = 1;
/* 启动线程,接受数据 */
recvFlag = true;
tudpr = new TUDPR(true);
tudpr->Resume();
}
TUDPR是负责受信的线程,其类定义如下:
class TUDPR : public TThread
{
private:
protected:
void __fastcall Execute();
public:
__fastcall TUDPR(bool CreateSuspended);
};
线程内的完整处理如下:
#include <vcl.h>
#pragma hdrstop
#include <winsock.h>
#include "TUDPR.h"
#include "Monitor.h"
extern int m_sendRcvFlag;
extern SOCKET sock;
extern WSADATA wsaData;
extern SOCKADDR_IN sockaddr;
#pragma package(smart_init)
__fastcall TUDPR::TUDPR(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
void __fastcall TUDPR::Execute()
{
int result;
unsigned char rbuf[SNDRCVDATALEN];
/* 受信标志变量为真时接收数据 */
while(recvFlag)
{
result = recvfrom(sock,
rbuf,
SNDRCVDATALEN,
0,
NULL,
NULL
;
if( !recvFlag
{
break;
}
if(result == SOCKET_ERROR)
{
Application->MessageBoxA("Receive Error","Error",MB_OK);
WSACleanup();
return;
}
rbuf[result] = 0;
/* 参考1中的doLog注释 */
Moniter -> doLog(false , rbuf , result);
}
}
第三种方法在效率上可以满足要求了,但是需要管理线程,实现起来也明显要麻烦许多。
作者Blog:http://blog.csdn.net/findheart/ ;
出处
主要讨论一下数据的接受:
1.NMUDP控件
这个控件使用起来比较简单,设定监听端口,然后响应DataReceived事件就可以了,例如:
void __fastcall TMoniter::NMUDPDataReceived(TComponent *Sender,
int NumberBytes, AnsiString FromIP, int Port)
{
/* 用一个标志变量控制控件受信后是否执行需要的操作 */
if (recvFlag)
{
int rl;
/* 用于接受数据的内存 */
unsigned char rbuf[1024 * 9];
/* 控件的ReadBuffer方法,把接受到的数据存储到rbuf */
NMUDP -> ReadBuffer(rbuf , sizeof(rbuf) , rl);
/* 字符串结束 */
rbuf[rl]=0;
/* stream是事先定义的文件指针 */
if (stream != NULL)
{
/* 自编doLog函数,把接收数据写入日志文件 */
doLog( false , rbuf ,rl ;
}
}
}
这个控件的优点是使用简单、效率比较高,但是只支持2K的缓冲,所以上面开辟的9K内存是多余的。2K的限制使我在项目中不得不放弃了这个控件。
2.IdUDPServer控件
使用方法跟NMUDP差不多,响应UDPRead事件就可以了,例如:(注释参考1)
void __fastcall TMoniter::IdUDPServer1UDPRead(TObject *Sender,
TStream *AData, TIdSocketHandle *ABinding)
{
if (recvFlag)
{
int r1;
unsigned char rbuf[1024 * 9];
r1 = AData->Size;
/* 接受到的数据是存放在数据流AData中的,把它们读到rbuf里去 */
AData->Read(rbuf , r1);
rbuf[r1] = 0;
if (stream != NULL)
{
doLog( false , rbuf ,r1);
}
}
}
这个控件支持了9K的缓冲,但是效率……我需要1秒钟接收150个1K多的数据包并解码后逐行显示在StringGrid中,虽然主要是对StringGrid的描绘浪费时间,但IdUDPServer还是不能令人满意。
3.回归自然吧——Socket
两个控件都不能满足我的需要,那么只能回头考虑底层的socket(我的C不好,对这个方法现在还不是很明白,所以注释很少,不过通过代码能大约猜出其功能)。
先定义这三个东东:
SOCKET sock
WSADATA wsaData
SOCKADDR_IN sockaddr
然后在需要开始受信的地方进行socket初始化,这里我用了一个按钮:
int result;
WORD wVersionRequested;
wVersionRequested = MAKEWORD(1,1);
if((result = WSAStartup(wVersionRequested,&wsaData))!=0)
{
Application->MessageBoxA("Socket Initial Error","Error",MB_OK);
WSACleanup();
return;
}
memset(&sockaddr,0,sizeof(sockaddr));
/* 设置端口号 */
sockaddr.sin_port=htons(3000);
sockaddr.sin_family=AF_INET;
sockaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock == INVALID_SOCKET)
{
Application->MessageBoxA("Socket Open failed","Error",MB_OK);
WSACleanup();
return;
}
result = bind(sock,(LPSOCKADDR)&sockaddr,sizeof sockaddr);
if(result == SOCKET_ERROR)
{
Application->MessageBoxA("Bind Error","Error",MB_OK);
WSACleanup();
return;
}
/* 自写函数getFileReady打开一个日志文件等待记录数据 */
if( !getFileReady()
{
WSACleanup();
return;
}
/* 把StringGrid编辑区域清理一下 */
sgLog -> RowCount = 2;
sgLog -> Rows[1] -> Clear();
sgLog -> Cells[0][1] = "1";
lineCount = 1;
/* 启动线程,接受数据 */
recvFlag = true;
tudpr = new TUDPR(true);
tudpr->Resume();
}
TUDPR是负责受信的线程,其类定义如下:
class TUDPR : public TThread
{
private:
protected:
void __fastcall Execute();
public:
__fastcall TUDPR(bool CreateSuspended);
};
线程内的完整处理如下:
#include <vcl.h>
#pragma hdrstop
#include <winsock.h>
#include "TUDPR.h"
#include "Monitor.h"
extern int m_sendRcvFlag;
extern SOCKET sock;
extern WSADATA wsaData;
extern SOCKADDR_IN sockaddr;
#pragma package(smart_init)
__fastcall TUDPR::TUDPR(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
void __fastcall TUDPR::Execute()
{
int result;
unsigned char rbuf[SNDRCVDATALEN];
/* 受信标志变量为真时接收数据 */
while(recvFlag)
{
result = recvfrom(sock,
rbuf,
SNDRCVDATALEN,
0,
NULL,
NULL
;
if( !recvFlag
{
break;
}
if(result == SOCKET_ERROR)
{
Application->MessageBoxA("Receive Error","Error",MB_OK);
WSACleanup();
return;
}
rbuf[result] = 0;
/* 参考1中的doLog注释 */
Moniter -> doLog(false , rbuf , result);
}
}
第三种方法在效率上可以满足要求了,但是需要管理线程,实现起来也明显要麻烦许多。
作者Blog:http://blog.csdn.net/findheart/ ;
- C++ Builder下三种UDP通信实现方法的比较[转]
- C++ Builder下三种UDP通信实现方法的比较
- C++ Builder下三种UDP通信实现方法的比较
- C++ Builder下三种UDP通信实现方法的比较
- C++ Builder下三种UDP通信实现方法比较
- C++ Builder下三种UDP通信实现方法比较
- C++ Builder下三种UDP通信实现方法的比较 选择自 findheart 的 Blog
- C++ Builder下三种UDP通信实现方法的比较 选择自 findheart 的 Blog
- C++Builder 实现功能比较完整的托盘程序
- Linux C实现简单的UDP服务器客户端通信
- Linux下C语言实现简单的udp通信
- UDP实现的广播通信
- C语言--利用UDP实现socket通信
- C++Builder下实现对端口读写的两种方法(转)
- [转] UDP/TCP穿越NAT的P2P通信方法
- vc串口通信3种方法的实现和比较
- 【C语言】【unix c】编写代码实现基于UDP的网络通信
- UDP/TCP穿越NAT的P2P通信方法研究(UDP/TCP打洞 Hole Punching)【转】
- 亲手编译uClinux的体验全记录
- 在你立足处深挖下去
- 捕捉listView_AfterLabelEdit后的label值
- 搜索的未来(4)
- Smartphone五星级软件推荐
- C++ Builder下三种UDP通信实现方法的比较[转]
- AB RsLogix5000 PLC第三方模块MVI56的编程开发
- 两种加密技术共同构建安全的ASP.NET数据访问
- 什么是供应链管理?
- 【程序14】
- [转帖] 关于sizeof()的一些思考
- 干那行,爱那行!
- [转贴]MFC程序员的WTL指南: 中文版序言
- [JAVA]在Junit中测试私有函数的方法(junit, private, method)