Theron分布式编程

我们将使用多个基于Theron开发的应用程序通过网络构建一个分布式应用。我们将建立一个简单的客户端/服务端的系统。在这个系统中,客户端发送消息给服务端,而且两个部分分别运行在不同的主机上。

在这个例子中,服务端是一个文本打印软件,将接受到的消息答应出来并发送给客户端。客户端则一直处于循环状态中,通过命令行接受字符串类型的文本并发送给服务端答应。

首先,我们需要一个消息类型,能够代表客户端和服务端通信的文本数据。我们在这两个应用程序中,同时定义相同的消息类型,名字也相同,如下:

// Simple message type that can be copied with memcpy so safely sent over the network. 
struct TextMessage 
{ 
    explicit TextMessage(const char *const text) 
    { 
        mText[0] = '\0'; 
        strcpy(mText, text); 
    } 

    char mText[256]; 
}; 

// In order to be sent over the network, message types must be registered. 
THERON_REGISTER_MESSAGE(TextMessage); 

为了能让消息通过网络发送至其他主机的应用程序中,消息的类型必须现在发送和接受的两端中注册。这样,他们才能识别特定的数据类型。通过网络分发的消息我们成为远端消息(remote messages)。远端消息必须满足一系列严格需求,而不仅仅是可复制这么简单。当前的消息通过简单的函数memcpy被复制到网络消息缓存中,这意味着消息类型当中不能包含指针类型的成员变量。

The fact that network messages are currently copied trivially by means of memcpy when sent over the network has another important implication: they must have the exact same memory layout in both the sending and receiving applications. In general both platforms must have the same word size and endianness, and both applications must have been built with the same compiler. These limitations will be relaxed in later versions.

 定义好我们的消息类型之后,让我们看一下客户端的程序结构:

int main(int argc, char *argv[]) 
{ 
    char buffer[256] = { '\0' }; 

    // Create a local endpoint. 
    // The location string is of the from tcp://ip-address:port, 
    // where tcp is the network protocol, and port is an arbitary port number. 
    sprintf(buffer, "tcp://%s:5556", argv[1]); 
    Theron::EndPoint endPoint("client", buffer); 

    // Connect to the remote endpoint. we must explicitly 
    //connect it to EndPoint in remote applications.
    sprintf(buffer, "tcp://%s:5555", argv[2]); 
    if (!endPoint.Connect(buffer)) 
    { 
        printf("ERROR: Connection failed - check networking is enabled.\n"); 
        return 1; 
    } 

    // The framework is tied to the endpoint. 
    Theron::Framework framework(endPoint); 

    // Send messages to the server in a loop until the user enters 'exit'. 
    // Note that if the server hasn't started listening yet it may miss the first messages!
    printf("Enter lines of text (max 256 chars per line). Type 'exit' to end.\n"); 

    while (strcmp(buffer, "exit") != 0) 
    { 
        // Send the text in a messages to the remote 'printer' actor using its unique name.
        gets(buffer); 
        framework.Send( 
            TextMessage(buffer), 
            Theron::Address(), 
            Theron::Address("printer")); 
    } 
} 

在Theron中,支持分布式编程的核心功能是Theron:: EndPoint 类,它代表了主机所在的网络地址。

接下来,就来看一下服务端的代码。服务端是由单个actor构成,称之为Printer。

class Printer : public Theron::Actor 
{ 
public: 

    Printer(Theron::Framework &framework, const char *const name) : 
      Theron::Actor(framework, name) 
    { 
        RegisterHandler(this, &Printer::Handler); 
    } 

private: 

    void Handler(const TextMessage &message, const Theron::Address from) 
    { 
        printf("%s\n", message.mText); 
        if (strcmp(message.mText, "exit") == 0) 
        { 
            // Signal we're done. 
            Send(0, Theron::Address("receiver")); 
        } 
    } 
}; 

其中,Printer是构造函数,主要工作就是注册该actor的消息处理方法。Handler就是消息处理方法了,第一个参数为接受的消息,第二个参数为发送该消息的地址(此地址为Theron内部统一的地址,对编程人员是透明的。一个actor的地址可通过GetAddress()方法获得)。Theron::Address()方法可以直接通过主机的ID(此处为receiver)获取相应的地址。

在服务端的主函数中设置了本地的EndPoint,只有名字和客户端不同。如下所示:

int main(int argc, char *argv[]) 
{ 
    char buffer[256] = { '\0' }; 

    // Create a local endpoint. 
    sprintf(buffer, "tcp://%s:5555", argv[1]); 
    Theron::EndPoint endPoint("server", buffer); 

    // Connect to the remote endpoint. 
    sprintf(buffer, "tcp://%s:5556", argv[2]); 
    if (!endPoint.Connect(buffer)) 
    { 
        printf("ERROR: Connection failed - check networking is enabled.\n"); 
        return 1; 
    } 

    // The framework and receiver are tied to the endpoint. 
    Theron::Receiver receiver(endPoint, "receiver"); 
    Theron::Framework framework(endPoint); 

    // The unique name of the actor allows the client to send it messages remotely. 
    Printer printer(framework, "printer"); 

    receiver.Wait(); 
} 

一旦EndPoint构建完成之后,Theron框架和应用程序中的接收者就能够通过构造函数中的参数绑定到Endpoint中。将框架和Endpoint绑定在一起,允许其中的actors能够通过框架收发消息。

注意,这个时候Printer类的构造函数和不太相同,Theron重载了Actor类的构造函数以适应不同的应用场景。在单节点中,无需指定actor的name参数,在分布式中,需要唯一指定name参数,作为actor的id,方便用户进行通信。当然,用户没有指定的情况下,系统也会自动生成的。但是更提倡用户指定,因为可以方便指定通信关系。

If no user-defined names are provided for actors and receivers then default names will be generated automatically. The default names identify the actor or receiver within the EndPoint it's tied to, and so will be unique so long as the EndPoint names are themselves unique. 

The advantage of supplying user-defined names is that user-defined names can be known, by common agreement, by actors on remote hosts.

在本文中,我们学会了如何使用Theron的EndPoint概念进行分布式编程。 

 

原文地址:http://www.theron-library.com/index.php?t=page&p=client%20server

转载于:https://my.oschina.net/wanborj/blog/854547

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值