您的位置:首页 > 运维架构

C#使用socket实现FTP、POP3、SMTP的客户端 (二)

2017-06-25 17:09 435 查看

概述

socket本质是编程接口,是对TCP/IP的封装。

TCP/IP是传输层的协议。

FTP、POP3、SMTP都是应用层的协议,是基于TCP/IP协议的。

所以,我们使用socket实现上述几种协议的客户端,其实是对借助socket对TCP/IP数据传输的封装基础,再往上封装一层的。

FTP客户端

C#使用socket实现FTP、POP3、SMTP的客户端 (一)

POP3客户端

界面图:



控件由以下组成:

- 五个textbox:tb_POPServer, tb_username, tb_password, tb_message, tb_ID

- 一个listbox:lsb_status

- 四个button:btn_saveSettings, btn_connect, btn_disconnect, btn_Receive

该POP3客户端主要实现的就是接收邮件功能了,然而并没有实现邮件内容解析功能

头文件:

using System;
using System.Windows.Forms;
using System.Net.Sockets;
using System.IO;


Sockets包是肯定要的,IO主要是为了使用NetworkStream类来方便socket的读写

全局变量:

#region Private Variables

private TcpClient Server;
private NetworkStream StrmWtr;
private StreamReader StrmRdr;
private String cmdData;
private byte[] szData;
private const String CRLF = "\r\n";

#endregion


POP3只需要建立一个连接,客户端向服务器发命令,服务器向客户端返回数据就行了。

主要用到的POP3命令如下:

命令描述
USER <用户名>登录POP3服务器的用户名
PASS <密码>登录POP3服务器的密码
STAT返回邮箱状态
QUIT断开连接
RETR [num]返回第num封邮件的内容
(建议使用网易163邮箱,QQ的邮箱有SSL加密,好像挺麻烦的。使用POP3服务和SMTP服务需要登录邮箱,在“设置”里面打开POP3服务和SMTP服务授权。)

注意:PASS的密码是授权码,不是你登录邮箱的密码!

全局函数:

#region Private Functions

/// <summary>
/// 获取命令端口返回结果,并记录在lsb_status上
/// </summary>
private String getSatus()
{
String ret = StrmRdr.ReadLine();
lsb_status.Items.Add(ret);
lsb_status.SelectedIndex = lsb_status.Items.Count - 1;
return ret;
}

#endregion


这几行代码重用太多了,索性拉出来写成函数了

连接按键(btn_connect)&断开连接(btn_disconnect):

#region Button:  Connect & Disconnect

private void btn_connect_Click(object sender, EventArgs e)
{
Cursor cr = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
Server = new TcpClient(tb_POPServer.Text, 110);
lsb_status.Items.Clear();

try
{
StrmWtr = Server.GetStream();
StrmRdr = new StreamReader(Server.GetStream());
this.getSatus();

string ret;

//Login
cmdData = "USER " + tb_username.Text + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(cmdData.ToCharArray());
StrmWtr.Write(szData, 0, szData.Length);
this.getSatus();

cmdData = "PASS " + tb_password.Text + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(cmdData.ToCharArray());
StrmWtr.Write(szData, 0, szData.Length);
ret = this.getSatus();
if (ret[0] == '-') throw new InvalidOperationException("用户名密码错误");

//Get Email's Info
cmdData = "STAT" + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(cmdData.ToCharArray());
StrmWtr.Write(szData, 0, szData.Length);
this.getSatus();

btn_connect.Enabled = false;
btn_disconnect.Enabled = true;
btn_Receive.Enabled = true;

}
catch (InvalidOperationException err)
{
lsb_status.Items.Add("ERROR: " + err.Message.ToString());
}
finally
{
Cursor.Current = cr;
}
}

private void btn_disconnect_Click(object sender, EventArgs e)
{
Cursor cr = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;

//Logout
cmdData = "QUIT" + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(cmdData.ToCharArray());
StrmWtr.Write(szData, 0, szData.Length);
this.getSatus();

StrmWtr.Close();
StrmRdr.Close();

btn_connect.Enabled = true;
btn_disconnect.Enabled = false;
btn_Receive.Enabled = false;

Cursor.Current = cr;

}

#endregion


简单又重复,就是通过socket发命令,再通过socket接数据,没啥特别的

(就连解析字符串,然后显示有几封邮件的代码我都没写)

(因为一写,强迫症绝壁会打算把整封邮件的内容一起解析了)

接收邮件按键(btn_Receive):

#region Button:  Receive Email

private void btn_Receive_Click(object sender, EventArgs e)
{
Cursor cr = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
string szTemp;
tb_message.Clear();

try
{
cmdData = "RETR " + tb_ID.Text + CRLF;
szData = System.Text.Encoding.ASCII.GetBytes(cmdData.ToCharArray());
StrmWtr.Write(szData, 0, szData.Length);
szTemp = this.getSatus();

if (szTemp[0] != '-')
{
while (szTemp != ".")
{
tb_message.Text += szTemp + "\r\n";
szTemp = StrmRdr.ReadLine();
}
}
}
catch (InvalidOperationException err)
{
lsb_status.Items.Add("ERROR: " + err.Message.ToString());

}
}

#endregion


强迫症忍住了,没把邮件解析出来……直接返回了socket收到的数据

SMTP客户端

C#使用socket实现FTP、POP3、SMTP的客户端 (三)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: