美文网首页
例题5-11 邮件传输代理的交互

例题5-11 邮件传输代理的交互

作者: 费曼JW | 来源:发表于2019-05-30 13:11 被阅读0次

    题目链接:UVaoj 814 The Letter Carrier's Rounds

    UVa814
    题目翻译:

    对于电子邮件应用程序,您将描述在成对MTA之间发生的基于SMTP的通信。发件人的用户代理向发送邮件传输代理(MTA)提供格式化邮件。发送MTA使用简单邮件传输协议(SMTP)与接收MTA通信。接收MTA将邮件传递给收件人的用户代理。通信链路初始化后,发送MTA将命令行(一次一行)发送给接收MTA,接收MTA在处理每个命令后返回三位编码的响应。发送方命令按每条消息的发送顺序显示如下。当同一消息发送到同一MTA的多个用户时,存在多个RCPT TO行。发送给不同MTA用户的邮件需要单独的SMTP会话。

    HELO myname 向接收者标识发送者(是的,只有一个l)
    MAIL FROM:<sender> 标识邮件发件人
    RCPT TO:<user> 标识消息的一个收件人
    DATA 后接任意数量的文本行,包含消息正文,以第1列中包含句点的行结尾。
    QUIT 终止通信

    接收MTA发送以下响应代码:
    221 关闭连接(退出后)
    250 操作正常(MAIL FROM和RCPT TO发送邮件到指定可接受的用户或发生消息后)
    354 开始发送邮件(在数据之后)
    550 不接受指令;此处没有此类用户(在RCPT TO之后,未知用户)
    输入:
    输入包含MTA的描述,后跟任意数量的消息。每个MTA描述都以MTA名称及其名称(1到15个字母数字字符)开头。MTA名称后面是在该MTA接收邮件的用户数和用户列表(每个用户1到15个字母数字字符)。MTA描述以第1列中的星号终止。每条消息以发送用户的名称开始,后跟一个收件人标识符列表。每个标识符的格式都是user@mtaname。消息(每行不超过72个字符)以第1列中的星号开始和结束。第1列中带星号的行(而不是发送方和收件人列表)表示整个输入的结束。
    输出:
    对于每条消息,显示发送和接收MTA之间的通信。邮件中提到的每个MTA都是有效的MTA;但是,目标MTA中可能不存在邮件收件人。接收MTA通过使用550代码响应rcpt to命令来拒绝这些用户的邮件。拒绝不会影响在同一MTA上传递给授权用户。如果在特定MTA中没有至少一个授权收件人,则不会发送数据。只有一个SMTP会话用于向特定MTA的用户发送邮件。例如,发送给同一MTA中5个用户的邮件将只有一个SMTP会话。另外,一条消息只发送给同一个用户一次。发送方联系接收MTA的顺序与输入文件中的顺序相同。如示例输出所示,在通信前面加上正在通信的MTA名称,并缩进每个非空的通信行。不应打印内部空间。

    思路:

    本题的任务为模拟发送邮件时MTA(邮件传输代理)之间的交互。所谓MTA,就是email地址格式user@mtaname的“后面部分”。当某人从user1@mta1发送给另一个人user2@mta2时,这两个MTA将会通信。如果两个收件人属于同一个MTA,发送者的MTA只需与这个MTA通信一次就可以把邮件发送给这两个人。

    本题可以用3个步骤解决:
    1.储存用户地址:使用string类型的vector容器储存每个用户的完整地址。如:user@MTA
    2.收件人MTA分类和顺序记录:定义一个vrctor(记录收件人MTA顺序)和map(MAT为键,string类型的vector容器(收件人地址)为值),对每一个收件人先分离MTA,在map中查MTA键值,若查得到则添加收件人地址到对应的值的vector容器中;若查不到则添加MTA为键string类型的vector容器为值到map中,添加这个MTA到记录顺序的vrctor中,再执行前一步操作。
    3.输出:在map中依次使用 记录收件人MTA顺序的vretor容器 作为键值得到对应的 收件人地址vrctor容器,在第一步的用户地址中查找 收件人地址容器 里的每一个地址,找到则存在用户。再格式化输出即可

    代码:
    #include<iostream>
    #include<string>
    #include<vector>
    #include<set>
    #include<map>
    using namespace std;
    
    void parse_address(const string& s, string& user, string& mta) {        //分离邮件地址,得到名字和MTA
      int k = s.find('@');
      user = s.substr(0, k);
      mta = s.substr(k+1);
    }
    
    int main() {
      int k;
      string s, t, user1, mta1, user2, mta2;
      set<string> addr;
    
      // 输入所有MTA,转化为地址列表
      while(cin >> s && s != "*") {
        cin >> s >> k;
        while(k--) { cin >> t; addr.insert(t + "@" + s); }      //储存所有用户完整地址
      }
    
      while(cin >> s && s != "*") {
        parse_address(s, user1, mta1);      //分离发件人地址
    
        vector<string> mta;     //所有需要连接的mta,按照输入顺序
        map<string, vector<string> > dest;      //每个mta需要发送的用户
        set<string> vis;        //记录收件人地址
        while(cin >> t && t != "*") {
          parse_address(t, user2, mta2);        //分离收件人地址
          if(vis.count(t)) continue;     //检查重复的收件人
          vis.insert(t);
          if(!dest.count(mta2)) { mta.push_back(mta2); dest[mta2] = vector<string>(); }
          dest[mta2].push_back(t);      //相同的MTA用户归类为到一个列表
        }
        getline(cin, t); // 把"*"这一行的回车吃掉
    
        // 输入邮件正文
        string data;
        while(getline(cin, t) && t[0] != '*') data += "     " + t + "\n";
    
        for(int i = 0; i < mta.size(); i++) {       //对每个MTA按顺序输出SMTP会话
          string mta2 = mta[i];
          vector<string> users = dest[mta2];        //读取该MTA下收件人地址
          cout << "Connection between " << mta1 << " and " << mta2 <<endl;
          cout << "     HELO " << mta1 << "\n";
          cout << "     250\n";
          cout << "     MAIL FROM:<" << s << ">\n";
          cout << "     250\n";
          bool ok = false;      //后用于判断是否输出数据
          for(int i = 0; i < users.size(); i++) {
            cout << "     RCPT TO:<" << users[i] << ">\n";
            if(addr.count(users[i])) { ok = true; cout << "     250\n"; }       //检查收件人是否在用户地址里
            else cout << "     550\n";
          }
          if(ok) {      //判断是否输出数据
            cout << "     DATA\n";
            cout << "     354\n";
            cout << data;
            cout << "     .\n";
            cout << "     250\n";
          }
          cout << "     QUIT\n";
          cout << "     221\n";
        }
      }
      return 0;
    }
    
    

    相关文章

      网友评论

          本文标题:例题5-11 邮件传输代理的交互

          本文链接:https://www.haomeiwen.com/subject/udjptctx.html