ACE6测试之ACE_SOCK_Stream

本文介绍了使用ACE库实现被动服务器通信的过程,包括创建被动服务器、监听客户端连接、接收数据和关闭连接的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       ACE中的流包装提供面向连接的通信。流数据传输包装类包括ACE_SOCK_Stream和ACE_LSOCK_Stream,连接建立类包括针对TCP/IP的ACE_SOCK_Connector和ACE_SOCK_Acceptor,以及针对UNIX域socket的ACE_LSOCK_Connector和ACE_LSOCK_Acceptor。

       1.下面创建一个被动服务器,侦听到来的客户连接。服务器接收来自客户的数据,然后关闭连接。连接关闭通过调用流上的close方法来完成,该方法会释放所有的socket资源并终止连接。

Server.h

#pragma once

#include "ace/Time_Value.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Stream.h"
#include "ace/Log_Msg.h"

#define SIZE_DATA 18
#define SIZE_BUF 1024
#define NO_ITERATIONS 5

class Server
{
public:
	Server(int port);
	~Server(void);
	int handle_connection();
	int accept_connections();
private:
	char *data_buf_;
	ACE_INET_Addr server_addr_;
	ACE_INET_Addr client_addr_;
	ACE_SOCK_Acceptor peer_acceptor_;
	ACE_SOCK_Stream new_stream_;
};

Server.cpp

#include "Server.h"

Server::Server( int port ):server_addr_(port),
	peer_acceptor_(server_addr_)
{
	data_buf_=new char[SIZE_BUF];
}


Server::~Server(void)
{
}

int Server::accept_connections()
{
	if(peer_acceptor_.get_local_addr(server_addr_)==-1)
		ACE_ERROR_RETURN ((LM_ERROR,"%p\n","Error in get_local_addr"),1);
	ACE_DEBUG ((LM_DEBUG,"Starting server at port %d\n",
		server_addr_.get_port_number()));
	while(1)
	{
		ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
		if(peer_acceptor_.accept(new_stream_,&client_addr_,&timeout)== -1)
		{
			ACE_ERROR((LM_ERROR,"%p\n","accept"));
			continue;
		}
		else
		{
			ACE_DEBUG((LM_DEBUG,
				"Connection established with remote %s: %d\n",
				client_addr_.get_host_name(),client_addr_.get_port_number()));
			///handle the connection
			handle_connection();
		}
	}
}

int Server::handle_connection()
{
	//read data from client
	for(int i=0; i< NO_ITERATIONS; i++)
	{
		int byte_count=0;
		if((byte_count=new_stream_.recv_n(data_buf_,SIZE_DATA,0))== -1)
			ACE_ERROR((LM_ERROR,"%p\n","Error in recv"));
		else
		{
			data_buf_[byte_count]=0;
			ACE_DEBUG((LM_DEBUG,"Server received %s \n",data_buf_));
		}
	}
	//close new endpoint
	if(new_stream_.close()== -1)
		ACE_ERROR((LM_ERROR,"%p\n","close"));
	return 0;
}
main.cpp

#include <QtCore/QCoreApplication>
#include "Server.h"
#include "ace/OS_NS_stdlib.h"

int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	if(argc< 2)
	{
		ACE_ERROR((LM_ERROR,"Usage %s <port_num>",argv[0]));
		ACE_OS::exit(1);
	}

	Server server(ACE_OS::atoi(argv[1]));
	server.accept_connections();

	return a.exec();
}

以上代码摘自:ACE程序员教程。
<think>首先,用户的问题是关于ACE_SOCK_Dgram的配置,以便自动绑定到本机IP地址。用户提到了ACE_SOCK_Dgram,这是ACE库中的一个类,用于处理UDP数据报协议。从引用中,我可以看出:-引用[1]讨论了一个函数,用于通过IP地址获取网络接口设备名,以便在ACE_SOCK_Dgram_Mcast中使用。-引用[2]提到了关于OPT_NULLIFACE_ALL和OPT_NULLIFACE_ONE选项,这些选项影响接口的选择。-引用[3]显示了ACE_SOCK_Dgram_Mcast的join方法调用。-引用[4]描述了ACE_SOCK类属,包括Dgram类用于UDP。用户的问题是:如何配置ACE_SOCK_Dgram来自动绑定本机IP地址。在ACE库中,ACE_SOCK_Dgram用于UDP通信。绑定到本机IP地址意味着在创建套接字时指定本地地址。标准做法:-当创建ACE_SOCK_Dgram时,你可以使用ACE_INET_Addr来指定本地地址和端口。-如果不指定,它可能会绑定到所有接口(0.0.0.0),或者根据系统默认行为。从引用中,特别是引用[2],它提到了选项如OPT_NULLIFACE_ALL和OPT_NULLIFACE_ONE,这些可能与绑定行为相关。关键点:-自动绑定到本机IP地址可能意味着绑定到一个特定的IP地址,而不是所有接口。-在ACE中,当你调用open方法时,你可以传递一个ACE_INET_Addr对象来指定本地地址。回顾ACE_SOCK_Dgram的文档:-ACE_SOCK_Dgram有一个open方法,可以接受一个本地地址。-例如:ACE_SOCK_Dgramdgram;ACE_INET_Addrlocal_addr(port,ip_address);dgram.open(local_addr);如果用户想自动绑定到本机IP地址,他们需要指定那个IP地址。从引用[1]中,用户提到了一个函数来通过IP获取设备名,但用户的问题是关于绑定IP地址,而不是设备名。在ACE中,绑定到IP地址时,你不需要设备名;你可以直接指定IP地址。在引用[3]中,join方法用于多播,但绑定是open方法的一部分。回答结构:-系统指令要求回答结构清晰,帮助用户逐步解决问题。-使用中文回答。-生成相关问题。-在引用的段落末尾添加引用标识。首先,回答用户的问题:1.解释如何配置ACE_SOCK_Dgram来自动绑定本机IP地址。2.提供代码示例。3.参考引用。步骤:-创建一个ACE_SOCK_Dgram对象。-创建一个ACE_INET_Addr对象,指定本机IP地址和端口。-调用open方法绑定到该地址。从引用[4]:"Dgram类基于UDP数据报协议...Stream类用于在连接建立之后提供双向的数据流。"对于绑定:-在UDP中,绑定是显式的,通过调用bind函数。在ACE_SOCK_Dgram中:-构造函数或open方法可以指定本地地址。标准方式:-ACE_SOCK_Dgramdgram;-ACE_INET_Addrlocal_addr(port,"192.168.1.100");//指定IP-intresult=dgram.open(local_addr);如果不指定IP,只指定端口,它会绑定到INADDR_ANY,即所有接口。用户想自动绑定到本机IP地址,意思是绑定到特定的IP地址,而不是所有接口。所以,他们需要在open方法中明确指定IP地址。如何自动获取本机IP地址?-用户可能想知道如何动态获取本机IP地址并绑定。-引用[1]中有一个函数get_bind_nic,但它返回设备名,不是IP地址。用户需要IP地址。在绑定中,你使用IP地址,不是设备名。在ACE中,ACE_INET_Addr接受IP地址字符串。所以,要自动绑定:1.获取本机的一个IP地址(例如,通过枚举接口)。2.然后使用那个IP地址创建ACE_INET_Addr。3.调用dgram.open(local_addr)。从引用[1],用户提供了get_bind_nic函数,但它返回设备名。在ACE_SOCK_Dgram的join或绑定中,可能需要设备名,但标准绑定使用IP地址。在引用[3]中:mcast_dgram_.join(m_mcastAddr,1,ACE_TEXT_CHAR_TO_TCHAR(KeyExtractCfg::instance()->GetMuticastInf().c_str()));这里,join方法有一个参数是设备名。但用户的问题是关于ACE_SOCK_Dgram,不是ACE_SOCK_Dgram_Mcast。ACE_SOCK_Dgram_Mcast是多播版本。用户说:"ACE_SOCK_Dgram",但从上下文,可能指的是多播版本,因为引用中有_Mcast。检查用户消息:"请问ACE_SOCK_Dgram如何配置才能自动绑定本机IP地址"但在引用中,有ACE_SOCK_Dgram_Mcast。在引用[4],ACE_SOCK_Dgram是基础类。ACE_SOCK_Dgram_Mcast继承自ACE_SOCK_Dgram。对于多播绑定,可能需要指定接口名或IP。但在标准UDP绑定中,对于单播,你可以直接绑定到IP地址。为了回答:-假设用户想绑定到特定IP地址。步骤:1.创建ACE_INET_Addr对象,指定IP和端口。2.调用ACE_SOCK_Dgram的open方法。如果用户想自动选择本机IP地址,他们需要获取IP地址列表。ACE中有方法来获取接口信息。例如,使用ACE::get_ip_interfaces或类似函数。在引用[1],用户有代码使用ioctl来获取接口信息。所以,在回答中:-解释如何手动指定IP。-解释如何自动获取并绑定。生成相关问题:-根据系统指令:"生成相关问题",在回答后添加。回答结构:-先直接回答问题。-然后提供代码示例。-添加引用标识。-最后添加相关问题。使用中文。最终回答大纲:1.介绍:ACE_SOCK_Dgram用于UDP通信,绑定本地地址通过open方法。2.手动绑定:指定IP地址在ACE_INET_Addr。3.自动绑定:获取本机IP地址并绑定。4.代码示例。5.参考引用。6.相关问题。</think>### ACE_SOCK_Dgram 自动绑定本机 IP 地址的配置方法 在 ACE(Adaptive Communication Environment)库中,`ACE_SOCK_Dgram` 用于实现 UDP 数据报通信。自动绑定本机 IP 地址意味着在创建套接字时,程序能动态选择并绑定到本地的一个有效 IP 地址,而不是默认绑定到所有接口(`0.0.0.0`)。这可以通过以下步骤实现: #### 步骤 1: 理解绑定机制 - `ACE_SOCK_Dgram` 的绑定通过 `open()` 方法完成,该方法接受一个 `ACE_INET_Addr` 对象作为参数,指定本地 IP 地址和端口。 - 如果不指定 IP 地址(例如,只指定端口),套接字会绑定到 `INADDR_ANY`(所有接口),这不是用户期望的“自动绑定本机 IP 地址”行为[^4]。 - 要实现自动绑定,需要先获取本机的有效 IP 地址,然后在 `open()` 中使用该地址。 #### 步骤 2: 获取本机 IP 地址 - 使用 ACE 的接口查询功能(如 `ioctl` 系统调用)枚举网络接口,并选择匹配的 IP 地址。 - 参考引用[1]中的函数 `get_bind_nic`,它通过 IP 地址获取设备名,但我们需要类似逻辑获取 IP 地址本身。以下是优化后的函数,用于获取本机 IP 地址列表并选择一个有效地址: ```cpp #include <ace/SOCK_Dgram.h> #include <ace/OS_NS_sys_socket.h> #include <ace/OS_NS_netdb.h> #include <net/if.h> std::string get_local_ip() { ACE_SOCK_Dgram so(ACE_INET_Addr((u_short)0)); // 创建临时套接字 ifreq if_buf[16]; ifconf ifc; ifc.ifc_len = sizeof(if_buf); ifc.ifc_buf = (caddr_t)if_buf; // 获取接口配置 if (ACE_OS::ioctl(so.get_handle(), SIOCGIFCONF, &ifc) == 0) { int nic_count = ifc.ifc_len / sizeof(ifreq); for (int i = 0; i < nic_count; ++i) { struct ifreq *item = &if_buf[i]; // 获取接口 IP 地址 if (ACE_OS::ioctl(so.get_handle(), SIOCGIFADDR, item) == 0) { sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&item->ifr_addr); std::string ip = ACE_OS::inet_ntoa(addr->sin_addr); // 排除环回地址 (127.0.0.1) if (ip != "127.0.0.1") { return ip; // 返回第一个非环回 IP 地址 } } } } return "0.0.0.0"; // 默认返回所有接口 } ``` 此函数返回本机的第一个非环回 IP 地址,适用于大多数场景。如果需要绑定到特定接口(如多播),可扩展逻辑[^1][^2]。 #### 步骤 3: 配置 ACE_SOCK_Dgram 自动绑定 - 使用获取的 IP 地址创建 `ACE_INET_Addr` 对象,然后调用 `open()` 方法绑定。 - 代码示例: ```cpp #include <ace/SOCK_Dgram.h> #include <ace/INET_Addr.h> #include <iostream> int main() { ACE_SOCK_Dgram dgram; u_short port = 12345; // 指定端口号 // 获取本机 IP 地址 std::string local_ip = get_local_ip(); if (local_ip == "0.0.0.0") { std::cerr << "Failed to get local IP, binding to all interfaces." << std::endl; } // 创建本地地址对象 ACE_INET_Addr local_addr(port, local_ip.c_str()); // 绑定到本机 IP 地址 if (dgram.open(local_addr) == -1) { ACE_ERROR_RETURN((LM_ERROR, "Bind failed: %p\n", "open"), 1); } else { std::cout << "Bound to IP: " << local_ip << " Port: " << port << std::endl; } // 后续使用 dgram 进行 UDP 通信... return 0; } ``` - **关键点**: - `open(local_addr)` 将套接字绑定到指定 IP 和端口。 - 如果 `get_local_ip()` 失败(例如返回 `0.0.0.0`),则回退到绑定所有接口。 - 对于多播场景(如 `ACE_SOCK_Dgram_Mcast`),可能需要额外调用 `join()` 并指定接口名,但绑定 IP 地址是基础[^3][^4]。 #### 注意事项 - **平台兼容性**:`ioctl` 调用在 Linux/Unix 上有效,Windows 平台需使用 `ACE_HAS_GETIFADDRS` 宏或其他方法(如 `ACE::get_ip_interfaces()`)[^2]。 - **错误处理**:如果系统只有一个接口或使用默认接口,可参考 `OPT_NULLIFACE_ALL` 和 `OPT_NULLIFACE_ONE` 选项简化逻辑[^2]。 - **性能**:动态获取 IP 地址会增加少量开销,建议在初始化时执行一次。 通过以上步骤,`ACE_SOCK_Dgram` 可自动绑定到本机 IP 地址,确保 UDP 通信基于特定网络接口[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值