ACE_Select_Reactor 2 —— 服务器网关

本文深入解析了使用ACE库进行基于Socket的服务器端与客户端通信的实现方式,包括创建被动服务器监听连接、接收客户端数据、关闭连接等关键步骤。同时,介绍了客户端如何主动连接服务器并发送数据。通过示例代码,详细展示了如何利用ACE库中的Socket类进行高效的数据传输。

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

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

 

 

class Server
{
public:
	Server (int port): server_addr_(port),peer_acceptor_(server_addr_)
	{
		data_buf_= new char[SIZE_BUF];
	}
	int handle_connection()
	{
		// Read data from client
			int byte_count=0;
			if( (byte_count=new_stream_.recv (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;
	}
	int 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();
			}
		}
	}
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类中,创建了一个被动服务器,侦听到来的客户端连接,在连接建立之后,服务器接收来自客户端的数据,然后关闭链接。

    Server类包含的accept_connection()方法使用接收器来将连接接受“进”ACE_SOCK_Stream new_stream_。该操作完成的基本流程是:调用接收器上的accept(),并将流作为参数传入其中。一旦连接已经建立进流中,流的包装方法send()和recv()就可以用来在新建立的链路上发送和接收数据,还有一个空的ACE_INET_Addr也被传入接收器的accept()方法,并在其中被设定为发起连接的远程机器地址。

    在连接建立后,服务器调用handle_connection()方法,它开始从客户端那里收取一个预先知道的单词,然后将流关闭。连接关闭通过调用流上的close()方法来完成,该方法会释放所有的Socket资源并终止连接。

 

    http://acme-ltt.iteye.com/blog/1455556中提到的ACE_Select_Reactor,在static ACE_THR_FUNC_RETURN controller (void *arg)函数中,调用上述的Server类,搭建基于ACE_Select_Reactor的Socket服务器网关。

 

 

    客户端程序:

 

#include "ace/SOCK_Connector.h"
#include "ace/INET_Addr.h"
#include "ace/OS.h"
#include "ace/Log_Msg.h"
#include <stdlib.h>
#include "text.h"
#include "ace/Thread_Manager.h"
#include <iostream>
#define SIZE_BUF 128
static const ACE_Time_Value TIME_INTERVAL(0, 1000000);
class Client
{
public:
	Client(char *hostname, int port):remote_addr_(port,hostname)
	{   
	    
		
	}
	int connect_to_server()
	{
		
		ACE_DEBUG ((LM_DEBUG, "(%P|%t) Starting connect to %s:%d\n",
			remote_addr_.get_host_name(),remote_addr_.get_port_number()));
		if (connector_.connect (client_stream_, remote_addr_) == -1)
			ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","connection failed"),-1);
		else
			ACE_DEBUG ((LM_DEBUG,"(%P|%t) connected to %s\n",
			remote_addr_.get_host_name ()));
		return 0;
	}
	
	int send_to_server()
	{
	    iovec iov[3];
	    iov[0].iov_base = (void *)"get";
	    iov[0].iov_len = 3;
	    iov[1].iov_base = getdata()/* some data */;
	    iov[1].iov_len = strlen(getdata());
	    iov[2].iov_base = (void *)"end.";
	    iov[2].iov_len = 4;
		
		if (client_stream_.sendv_n (iov,3) == -1)
		{
			ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","send_n"),0);
			//break;
			exit(0);
		}
		close();
	}
	int close()
	{
		if (client_stream_.close () == -1)
			ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","close"),-1);
		else
			return 0;
	}
private:
	ACE_SOCK_Stream client_stream_;
	ACE_INET_Addr remote_addr_;
	ACE_SOCK_Connector connector_;
	char *data_buf_;
};
int main (int argc, char *argv[])
{
	if(argc<3)
	{
		ACE_DEBUG((LM_DEBUG,”Usage %s <hostname> <port_number>\n”, argv[0]));
		ACE_OS::exit(1);
	}
	Client client(argv[1],ACE_OS::atoi(argv[2]));
	client.connect_to_server();
	client.send_to_server();
}

     客户端由单个Client类表示。Client含有connect_to_server()和send_to_server()方法。

    connect_to_server()方法使用类型为ACE_SOCK_Connector的连接器来主动地建立连接。连接的设置通过调用连接器上的connect()方法来完成:传入的参数为想要连接的机器的远程地址,以及用于在其中建立连接的空ACE_SOCK_Stream 。远程机器在运行时参数中指定。一旦connect()方法成功返回,通过使用ACE_SOCK_Stream封装类中的send()和recv()方法族,流就可以用于在新建立的链路上发送和接收数据。

 

    在该代码中,一旦连接建立好,send_to_server()方法就会被调用,将一个iovec类型的数组,用sendv_n()方法,发送到服务器上。

ACE_WFMO_ReactorACE(Adaptive Communication Environment)框架中的一个反应器实现,专门用于 Windows 平台。它基于 WaitForMultipleObjects 函数,提供了一种高效的事件驱动机制来处理多线程环境中的并发事件。 在多线程环境中,ACE_WFMO_Reactor 可以与多个线程协同工作,从而提高应用程序的并发处理能力。以下是一些关键点: 1. **事件处理**:ACE_WFMO_Reactor 可以注册多个事件处理器(Event Handlers),每个处理器可以处理不同类型的事件,如读、写、异常等。 2. **线程安全**:ACE_WFMO_Reactor 提供了线程安全的接口,确保在多线程环境下对反应器的操作不会导致数据竞争或死锁。 3. **并发处理**:通过将事件处理器分配给不同的线程,可以实现并发处理多个事件,提高系统的响应速度和吞吐量。 4. **同步机制**:ACE 提供了多种同步机制,如互斥锁(Mutex)、条件变量(Condition Variable)等,可以与 ACE_WFMO_Reactor 结合使用,以实现更复杂的并发控制。 5. **事件驱动**:ACE_WFMO_Reactor 采用事件驱动的方式,应用程序只需注册事件处理器并等待事件发生,而不需要显式地轮询或管理线程的调度。 以下是一个简单的示例,展示了如何在多线程环境中使用 ACE_WFMO_Reactor: ```cpp #include <ace/Reactor.h> #include <ace/Task.h> #include <ace/WFMO_Reactor.h> #include <ace/Thread_Manager.h> class My_Handler : public ACE_Event_Handler { public: virtual int handle_input(ACE_HANDLE handle) { // 处理输入事件 return 0; } virtual ACE_HANDLE get_handle() const { return ACE_STDIN; } }; class My_Task : public ACE_Task_Base { public: My_Task(ACE_Reactor *reactor) : reactor_(reactor) {} virtual int svc() { reactor_->owner(ACE_Thread::self()); reactor_->run_reactor_event_loop(); return 0; } private: ACE_Reactor *reactor_; }; int main() { ACE_WFMO_Reactor reactor; My_Handler handler; My_Task task(&reactor); task.activate(THR_NEW_LWP | THR_JOINABLE, 4); task.wait(); return 0; } ``` 在这个示例中,`My_Handler` 是事件处理器,`My_Task` 是处理事件的线程任务。`ACE_WFMO_Reactor` 被传递给多个线程任务,以实现并发处理事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值