我的邮箱客户端程序Popmail
05年的时候写了一个邮箱客户端程序。当时主要目的是研究POP3和SMTP协议,同时锻炼自己的网络编程能力。当然了,如果自己写的邮箱客户端能够满足自身的日常工作需要,而不是频繁的登录不同的网页邮箱,那就再好不过了。时隔16年,给popmail增加了SSL(TLS 1.2)会话,感觉安全了一点,邮件再也不用裸奔了,看到16年前的代码,非常感慨,随便写写,特此纪念。
POP3和SMTP这两个协议本身都很简单,但实现起来还是有很大难度,尤其是你希望把它写的健壮、易用或者产品化的时候。
比如HTTP协议也很简单,写个简单的socket程序通过GET命令就能把网页给down下来。但接收大的网络资源就复杂多了。何时解析、如何解析完整的HTTP响应头,就是个头疼问题。因为你不能指望一次recv就能接收完所有响应数据,也不能指望服务器先发送HTTP响应头,然后再发送响应数据。只有把HTTP响应头彻底解析了,我们才能知道后续接收的Body数据有多大,何时才能接收完毕。
比如通过响应头的"Content-Length"字段,才能知道后续Body的大小。这个大小可能超过了你之前开辟的接收数据缓存区大小。当然你可以在得知Body大小后,重新开辟一个与"Content-Length"一样大小的缓存区。但这样做显然是不明智的,比如你get的是一部4K高清蓝光小电影,蓝光电影不一定能get到,蓝屏电脑倒有可能get到。。。。。。
遇到服务器明确给出"Content-Length"字段,是一件值得额手称庆的大喜事,但不是每个IT民工都这么幸运。如果遇到的是不靠谱的服务器,发送的是"Transfer-Encoding: chunked",那你就必须锻炼自己真正的解析和组织能力了。这些分块传输的数据,显然不会以你接收的节奏到达你的缓冲区,比如先接收到一个block块大小,然后是一个完整的块数据,很有可能你会接收到多个块或者不完整的块,这就需要你站在宏观的角度把他们拼接起来。
如果你遇到的是甩的一米的服务器,它不仅给你的是chunked,而且还增加了"Content-Encoding: gzip",那么你就需要拼接后进行解压,当然你也可能遇到的是"deflate"压缩。
题外话:我一直困惑的是HTTP协议为何不是对分块数据单独gzip压缩然后传输,而只能是整体gzip压缩后再分块传输。这个对大资源传输很关键,比如上面的4K高清蓝光小电影,显然不能通过gzip+chunked方式传输,土豪服务器例外。
当然你也可以用开源的llhttp来解析收到的http数据,从而避免上述可能会遇到的各种坑。最新版本的nodejs中就使用llhttp代替之前的的http-parser,据说解析效率有大幅提升。为此我下载了nodejs源码,并编译了一把,这是一个快乐的过程,因为你可以看到v8引擎,openssl,zlib等各种开源库。。。。,不过llhttp只负责解析,不负责缓存,因此你还是需要在解析的过程中,进行数据缓存。这是我写的通过llhttp解析http响应数据的案例:
基于SSL(TLS)的HTTPS网页下载——如何编写健壮的可靠的网页下载
这里面有我封装好的sslite.dll库可以方便的帮助你进行SSL客户端通信,目前支持TLS1.2,我的popmail因为使用sslite库才把衣服穿上避免了裸奔。
花开两朵各表一枝,还是回到POP3/SMTP上来。
相较而言,实现POP3要比实现SMTP复杂,这个复杂不是指协议本身有多复杂,也不是POP3比SMTP多了几个命令,而是指用代码实现协议的难度,尤其是解析难度。POP3是接收协议,SMTP是发送协议,总体而言发送比接收要简单很多。
因为发送数据的时候你可以耍流氓,不管服务器的死活,可以变态的1个字节1个字节发数据,也可以忽长忽短的发数据,从而让服务器猜不透你,直到把数据全部发送完毕。但接收数据就复杂多了,比如上面提到的如何接收HTTP响应数据,现在需要你来面对猜不透的服务器了,因为服务器也可能耍流氓。
早期的email协议只支持ASCII码这种纯文本传输,后来随着富文本的出现,图像、文件也迫切需要通过email进行传输。这时MIME协议诞生了,MIME的出现更多的是一种向下兼容的无奈,而不是革命。通过对二进制数据或非ASCII码数据进行base64或quoted-printable编码,来实现纯ASCII码的传输。显然这种方式会让你的邮件体变大,传输效率下降。
传输下降只是一方面,解析MIME格式的邮件也是一件头疼的事,对于"Content-Type: multipart/mixed"来说,需要根据boundary值,将不同mixed part邮件体给解析出来。同时你要面临各种编码格式,否则你的邮件标题、附件名称就会出现乱码,比如这种:"=?gb2312?B?=",比如这种:"=?gb2312?Q?",又比如这种"=?unicode-1-1-utf-7?q?"。。。。,当时还还遇到过"Content-type: message/rfc822",或者"content-disposition : inline"字段,完全处于懵B状态。05年的时候,网上资料特别少,也不认识张小龙,张小龙不仅是微信之父,更是Foxmail之母。如果当时能联系上,可能会发微信咨询一下,或者qq加好友哦。。。。。。,但在当年只能连蒙带猜,遇到一次乱码就猜测着解析看看,敢于在踩雷中解析,在解析中踩雷。
当年写邮箱客户端使用的是经典的VC6.0,也许很多90后、00后、10后没有听说过它,没关系,没关系,下面就是用VC6编写的popmail,不高调,不奢华,一眼就能看出vc6的影子。它支持多邮箱账户、邮件自动接收、快速查看邮件列表、远程删除邮件,自动回复等人民群总喜闻乐见却基本不用的功能。
1、主界面
2、多邮箱账户配置
3、账户配置
4、自动规则设定
5、接收邮件
6、快速查看
为什么不能把界面写的多次多彩呢?VC6写的程序就是这样的,古朴大方。。。。。
我的邮箱客户端程序Popmail的更多相关文章
- 2015第37周二foxmail邮箱客户端迁移
foxmail7.0邮箱客户端迁移风波浪费我下午不少时间,不知为何做完foxmail客户端在卡的时候我将其强制关闭,然后将整个邮箱目录拷贝到一台新电脑上,运行客户端居然我要新建账户(账户信息丢失),将 ...
- javaWeb之邮箱发送(邮箱客户端配置)
这里使用的是本机的邮箱服务器 , 代码执行条件: 1.·邮箱服务器 , 下载地址 密码 s4xn 邮箱服务器配置: 1):安装 2):打开服务器 红色部分是默认账号,不用处理 3)系统设置 ...
- VC++ 使用ShellExecute函数调用邮箱客户端发送邮件(可以带附件)
之前写过一篇博文,通过MAPI实现调用邮箱客户端发送邮件带附件,当时对ShellExecute研究不深,以为ShellExecute不能带附件,因为项目需求原因(MAPI只能调用Foxmail和O ...
- VC++使用IMAPI调用Outlook邮箱客户端和Foxmail邮箱客户端遇到的问题
http://www.cnblogs.com/abiao/articles/303090.html 发送邮件 MAPISendMail() 发送邮件功能就是对MAPISendMail()的封装.下面解 ...
- 基于 SailingEase WinForm Framework 开发客户端程序(3:实现菜单/工具栏按钮的解耦及状态控制)
本系列文章将详细阐述客户端应用程序的设计理念,实现方法. 本系列文章以 SailingEase WinForm Framework 为基础进行设计并实现,但其中的设计理念及方法,亦适用于任何类型的客 ...
- php编写tcp服务器和客户端程序
这是我从别的地方看到的. 1.修改php.ini,打开extension=php_sockets.dll 2.客户端程序 SocketClient.php <?php set_time_limi ...
- 在公司内网上创建自己的 OSM.Planet 街道级别地图服务器及其客户端程序
转自我的BLOG http://blog.csdn.net/goldenhawking/article/details/6402775 最近经过陛下点拨,涉猎了“OpenStreetMap”,做了不 ...
- 使用 Socket 通信实现 FTP 客户端程序(来自IBM)
FTP 客户端如 FlashFXP,File Zilla 被广泛应用,原理上都是用底层的 Socket 来实现.FTP 客户端与服务器端进行数据交换必须建立两个套接字,一个作为命令通道,一个作为数据通 ...
- winform客户端程序第一次调用webservice方法很慢的解决方法
.net2.0的winform客户端最常用的与服务端通信方式是通过webservice,最近在用dottrace对客户端做性能测试的时候发现,客户端程序启动以后,第一次调用某一个webservice的 ...
随机推荐
- ant命令
ant -help 帮助(ant -h) ant -projecthelp 列举xml中重要的部分 (ant -p) ant -version 查看版本 ant -diagnostics 打印所有环境 ...
- javascript-初级-day05js函数传参
JS基础-01 函数传参.参数类型-1 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Conten ...
- 31、下一个排列 | 算法(leetode,附思维导图 + 全部解法)300题
零 标题:算法(leetode,附思维导图 + 全部解法)300题之(31)下一个排列 一 题目描述 二 解法总览(思维导图) 三 全部解法 1 方案1 1)代码: // 方案1 "双指针法 ...
- Yarp 让系统内调度更灵活
简介 Yarp 是微软团队开发的一个反向代理组件, 除了常规的 http 和 https 转换通讯,它最大的特点是可定制化,很容易根据特定场景开发出需要的定制代理通道. 详细介绍:https://de ...
- python故障
问题: ImportError: No module named dns.resolver 解决: 通过包管理工具pip安装dnspython pip install dnspython
- Hive-insert into table 与 insert overwrite table 区别
区分insert into 和 insert overowrite: 0. 命令格式 INSERT OVERWRITE|INTO TABLE tablename [PARTITION (partcol ...
- C++你不知道的事
class A { public: A() { cout<<"A's constructor"<<endl; } virtual ~A() { cout&l ...
- Deep Learning(深度学习)整理,RNN,CNN,BP
申明:本文非笔者原创,原文转载自:http://www.sigvc.org/bbs/thread-2187-1-3.html 4.2.初级(浅层)特征表示 既然像素级的特征表示方法没有作用,那怎 ...
- 【模板】单源最短路径(Dijkstra)/洛谷P4779
题目链接 https://www.luogu.com.cn/problem/P4779 题目大意 给定一个 \(n\) 个点 \(m\) 条边有向图,每个点有一个非负权值,求从 \(s\) 点出发,到 ...
- 作为Java技术面试官,我如何深挖候选人的技能
作为Java资深技术面试官,首先我感觉有必要讲解"面试官深挖问题"的动机,在了解动机的前提下,大家才能更好地准备面试.面试官为什么要在一个点上深挖?两大目的. 1 首先是通过深 ...