Chinaunix首页 | 论坛 | 博客
  • 博客访问: 539204
  • 博文数量: 252
  • 博客积分: 6057
  • 博客等级: 准将
  • 技术积分: 1635
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-21 10:17
文章分类

全部博文(252)

文章存档

2013年(1)

2012年(1)

2011年(32)

2010年(212)

2009年(6)

分类:

2010-07-12 14:49:13

C++ Builder下三种UDP通信实现方法的比较(1)

主要讨论一下数据的接受:
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;
    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
#pragma hdrstop
#include

#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);
    }
}


第三种方法在效率上可以满足要求 了,但是需要管理线程,实现起来也明显要麻烦许多。













阅读(2845) | 评论(8) | 转发(0) |
给主人留下些什么吧!~~

chulia200020012010-07-13 14:05:51

高分求UDP穿透NAT网关代码(Delphi) http://topic.csdn.net/t/20040419/21/2985054.html Delphi 网络测速器附源代码 http://www.codefans.net/soft/6803.shtml 利用DELPHI编程编写Socket通信程式 http://www.huinu.com/viewnews-41262.html

chinaunix网友2010-07-13 13:19:15

如何查看本机端口占用的程序 http://www.ieing.cn/html-37989-1.html 1. 在"运行"中输入CMD   2.在启动的窗口中输入netstat -ano,就可以看到所有端口占用的情况,记下占用80端口的程序的PID   3.打开"任务管理器",点击菜单栏的"查看",再点击"选择列",选上"PID(进程标识符)"   4.在进程中找个相应的PID值,结束进程即可   一、找出自身开放的端口   扫描端口,然后找漏洞是攻击者入侵的基本思路。可以说,机器上开放的端口越多,攻击者入侵的机会就越大,因此我们可以通过关闭一些我们不用的端口来提高电脑的安全性。   那如何知道我们的Windows XP开放了哪些端口呢?我们可以用命令"Netstat"来查看系统中开放的端口。   我们需要用到这个命令的两个参数:-a、-n。参数-a显示当前所有连接和侦听端口,而参数-n以数字格式显示地址和端口号(而不是尝试查找名称),两者可以结合起来使用:Netstatan(如图1),就能查看当前端口的开放情况。   

chinaunix网友2010-07-13 13:15:48

获得当前系统的tcp所有打开端口及ip地址 提交日期:2003-11-22 作者:cjsh 关键词:tcp 端口 ip地址 ip helper api //gettcptable函数单元 unit untiphlpapi; interface uses windows, sysutils, winsock; type eiphlperror = class(exception); //----------------tcp结构------------------------------------------------ ptmibtcprow = ^tmibtcprow; tmibtcprow = packed record dwstate : dword;//状态 dwlocaladdr

chulia200020012010-07-13 11:58:44

如何编写用TCP/IP的通讯程序 http://tech.ddvip.com/2006-03/11437446001179.html BCB 网络组件的使用 http://hi.baidu.com/jiemnij/blog/item/8a641cfa124a246c024f5678.html TServerSocket和TClientSocket 的使用 http://caimingdong2008.blog.163.com/blog/static/5045242920081021104037964/

chulia200020012010-07-13 11:46:52

请教:如何使用NMUDP控件实现UDP广播效果? http://topic.csdn.net/t/20010210/13/67463.html 哪位知道如何使用NMUDP控件实现UDP广播效果? 依稀记得是把接收IP设成一个特殊的地址就可以了,但不记得具体是什么了. 将IP设置为255.255.255.255试试!理论上是这样的,我没有条件测试! 这有篇文章:你可以看看! 利用特殊IP地址实现网络广播 我们在编制网络应用程序时,经常需要将一份消息同时发送给网络上的所有用户,这叫做消息的广播。网络消息的广播技术在编制多媒体网上演示、网络会议等程序时有重要的意义。   一、技术要点分析   本文所介绍的网络技术是利用IP协议中的特殊地址实现的。IP协议是建立TCP/IP网络的最基本协议,它定义了在整个TCP/IP网络上传输数据所用的基本单元。   在使用TCP/IP协议的网络环境中,一台计算机有一个主机地址,同时,一个网络也被分配了一个网络地址(见表1)。   为