通过socks5代理使用smtp发邮件

起因

因为使用smtp发邮件,点击查看邮件原文能看到发送的服务器ip,而一般使用smtp的服务器为后台服务器,为了防止ip暴露,所以需要通过代理来进行发邮件的动作。

为了完成这个需求,首先百度、谷歌了一遍没找到有能’参考‘的例子,因此只能自己想办法去实现。

思路1

之前使用过php的curl扩展中添加代理,因此很容易就想到用curl,而curl使用代理的相关例子也是比较容易找到,在curl中设置相关参数就可以。

curl_setopt($curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
curl_setopt($curl, CURLOPT_PROXY, "代理服务器ip");
curl_setopt($curl, CURLOPT_PROXYPORT, "代理端口");
curl_setopt($curl, CURLOPT_PROXYUSERPWD, "账号:密码");

而使用curl去发送smtp邮件的例子我也找到,参考这个帖子的例子php中通过curl smtp发送邮件虽然我不知道他的代码自己是不是能实现的,反正在我的环境PHP Version 7.1.26;cURL Information 7.61.1是报错的,提示curl的url不合法)。然后花了不少时间去查出错的原因(因为在phpinfo中看到cURL支持的协议有smtp、telnet,我觉得还能抢救一下),但是相关的用法没找到文档或例子。百度能搜到的只是刚刚参考的例子,谷歌搜到的使用curl发smtp邮件的完全没有。唯一相关的帖子回答大概意思是curl虽然支持简单的SMTP连接,但是不适合进行这种持续发送应答的tcp连接,最好使用sockets去完成,于是我使用了思路二的方式。

思路2

没办法使用curl(目前的能力不足)完成就只能使用sockets去连接了。没有办法偷懒,只能先去看一下socks5的协议和smtp的协议。这里难点其实是如何让socks5服务器连接上smtp服务器,连上以后又要如何让socks5服务器发消息给smtp服务器。而使用sockets去完成smtp发邮件的一整套流程,有比较多可以参考的资料。

smtp协议

对smtp协议没什么概念的话,建议可以参考一下一些使用cmd的telnet发送邮件的例子(随便贴一个例子),然后尝试使用telnet去发一封邮件。以qq的smtp服务器为例:(为回复消息)

  • telnet smtp.qq.com 587(220 smtp.qq.com Esmtp QQ Mail Server)
  • EHLO smtp.qq.com(250-smtp.qq.com 250-PIPELINING 250-SIZE 73400320 250-STARTTLS 250-AUTH LOGIN PLAIN 250-AUTH=LOGIN 250-MAILCOMPRESS 250 8BITMIME)
  • STARTTLS auth login(220 Ready to start TLS)
  • AUTH LOGIN(334 VXNlcm5hbWU6)
  • {base64加密后的qq邮箱账号}(334 VXNlcm5hbWU6)
  • {base64加密后的qq邮箱密码}(235 Authentication successful)
  • mail from: <发件人邮箱地址>(250 OK)
  • rcpt to:<接收人邮箱地址>(250 OK)
  • data(354 END DATA WITH <CR><LF>.<CR><LF>)(意思是空行加一个"." 代表结束)
  • 输入一些邮件的补充信息标题、日期、回复地址、版本 等等(其中标题如果是中文需要拼接一下成Subject:=?UTF-8?B?{base64加密标题}?= )
  • 正文
  • /*空一行*/
  • .(250 OK queued as)
    到这里就已经完成发送邮件了,可以看到自己的邮箱已经收到一封没有附件的邮件。我的代码中就是按照这种形式去完成的发送邮件。

socks5协议

接下来就是socks5协议,这里我找到一篇比较详细的帖子,对socks5服务器的一些应答有一定的解释说明socks5代理服务器协议说明。按照我需要的,我只需要完成几步:

  • 连上socks5服务器
  • 完成socks服务器认证
  • 让socks服务器连上smtp服务器

而我需要做的是:

  • 向代理服务器对应端口发送0x05 0x01 0x02 且服务器回复0x05 0x02 (5 1 2 说明是认证密码模式 还有不需要认证的模式 这里我就没有管这个 在上面的帖子有对不同的模式进行说明)
  • 向代理服务器发送0x01 代理服务器账号长度 代理服务器账号 代理服务器密码长度 代理服务器密码 且服务器回复0x01 0x00(发送0x01 固定,然后指定之后的多少个字节为账号 然后是账号 然后指定之后多少个字节为密码 然后是密码 服务器回复1 0说明认证成功)
  • 向代理服务器发送0x05 0x01 0x00 0x03 smtp服务器域名长度 smtp服务器域名 smtp服务器端口 且服务器回复0x05 0x00 0x00 0x01 再加上6位数字(发送5 1 0 3 说明让代理服务器 访问后面指定的域名和端口 如果是 ip 则发 5 1 0 1 回复的 前4位固定 后面6位表示代理服务器使用了哪个端口去进行连接)
测试时因为这个不能像smtp一样使用telnet去测试,所以这里我直接使用代码来测试
pfsockopen($this->proxyHost,$this->proxyPort,$errno,$errbuf, 60);//创建一个socket句柄
fwrite($this->sock, pack("C3", 0x05, 0x01, 0x02));//发送5 1 2
$res=fread($this->sock,512);//代理服务器回复的内容 这里直接打印出来是乱码,通过打印unpack('C'.strlen($res),$res) 可以查看返回值

到这里其实就已经完成了代理服务器的部分(就是这么简单),后面就是按smtp的协议直接发送,接收。

testSMTP.php例子代码

<?php
use Mail\ProxySMTP;require('ProxySMTP.php');
$SMTP=new ProxySMTP;
$SMTP->proxyHost="代理服务器ip";
$SMTP->proxyPort="代理服务器端口";
$SMTP->proxyUsername="代理服务器用户名";
$SMTP->proxyPassword= "代理服务器密码";
$SMTP->smtpHost='smtp.qq.com';//smtp服务器域名
$SMTP->smtpPort='587';//smtp服务器端口
$SMTP->smtpUsername='2592515244@qq.com';//填邮箱
$SMTP->smtpPassword='smtp服务器的账号对应的密码';//填设置里面的授权码 不是qq密码
$SMTP->title='测试标题';
$SMTP->content='测试内容';
$SMTP->from='2592515244@qq.com';//发信人 和账号一样
$SMTP->to='2592515244@qq.com';//接收人
$SMTP->attachment='TIM图片20190322105750.gif';//加附件路径
$return=$SMTP->send();
echo $return['msg'];
?>

ProxySMTP.php类的代码

<?php
namespace Mail;class ProxySMTP{//代理服务器ippublic $proxyHost;//代理服务器端口public $proxyPort;//代理服务器用户名public $proxyUsername;//代理服务器密码public $proxyPassword;//smtp 域名(不能是ip)ip需要改代理的报文前缀 5 1 0 3改成 5 1 0 1public $smtpHost;//smtp 端口public $smtpPort;//smtp用户名public $smtpUsername;//smtp授权码public $smtpPassword;//邮件标题public $title;//发件人邮箱public $from;//收件人邮箱public $to;//邮件正文public $content;//附件有效访问路径public $attachment='';//附件的相关变量protected $file_name;protected $file_type;protected $file_ext;//smtp判断指令结束符号 回车符+换行符protected $CRLF="\r\n";//socket句柄private $sock;//socks服务器连上smtp服务器状态private $connectSMTP=false;/*** 连接代理服务器,让代理服务器连接smtp服务器*** */protected function connect(){$this->sock = pfsockopen($this->proxyHost,$this->proxyPort,$errno,$errbuf, 60);if(!$this->sock){//连接失败return ['status'=>false,'errno'=>$errno,'errstr'=>$errbuf,'msg'=>'socks服务器连接失败'];}fwrite($this->sock, pack("C3", 0x05, 0x01, 0x02));if(fread($this->sock,512)!==pack('C2',0x05,0x02)){//socks服务器不支持密码认证模式return ['status'=>false,'errno'=>$errno,'errstr'=>$errbuf,'msg'=>'socks服务器不支持密码认证模式'];}fwrite($this->sock, pack('C2',0x01,strlen($this->proxyUsername)).$this->proxyUsername.pack('C1',strlen($this->proxyPassword)).$this->proxyPassword);if(fread($this->sock,512)!==pack('C2',0x01,0x00)){//socks服务器账号密码认证失败return ['status'=>false,'errno'=>$errno,'errstr'=>$errbuf,'msg'=>'socks服务器账号密码认证失败'];}fwrite($this->sock, pack("C5", 0x05 , 0x01 , 0x00 , 0x03, strlen($this->smtpHost)).$this->smtpHost.pack("n", $this->smtpPort));if(substr(fread($this->sock,512),0,4)!==pack('C4',0x05,0x00,0x00,0x01)){//socks服务器连接smtp服务器失败return ['status'=>false,'errno'=>$errno,'errstr'=>$errbuf,'msg'=>'socks服务器连接smtp服务器失败'];}else{$return=fread($this->sock,512);if(substr($return,0,3)!='220'){//smtp连接错误return ['status'=>false,'errno'=>$errno,'errstr'=>$errbuf,'msg'=>$return];}$this->connectSMTP=true;return ['status'=>true];}}/***检查必传字段是否设置好*** */protected function beforeSend(){$reflect =new \ReflectionClass($this);$arg=$reflect->getProperties(\ReflectionProperty::IS_PUBLIC);foreach($arg as $v){if($v->getName()!='attachment'){if(!$v->getValue($this)){return ['status'=>false,'msg'=>$v->getName().'不能为空'];}}}return ['status'=>true];}/*** 发邮件方法,连接代理服务器,让代理服务器连接smtp服务器并验证权限后发送*** */public function send(){$beforeSendCheck=$this->beforeSend();if(!$beforeSendCheck['status']){return $beforeSendCheck;}$connectStatus=$this->connect();if(!$connectStatus['status']){return $connectStatus;}$authStatus=$this->smtpAuth();if(!$authStatus['status']){return $authStatus;}$headerStatus=$this->smtpHeader();if(!$headerStatus['status']){return $headerStatus;}$bodyStatus=$this->smtpBody();if(!$bodyStatus['status']){return $bodyStatus;}return ['status'=>true,'msg'=>'发送成功'];}/*** 邮箱账号密码认证*** */protected function smtpAuth(){fputs($this->sock,'EHLO '.$this->smtpHost.$this->CRLF);fread($this->sock,512);fputs($this->sock,'STARTTLS auth login'.$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='220'){//不支持TLSreturn ['status'=>false,'msg'=>$return];}fputs($this->sock,'AUTH LOGIN'.$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='334'){//不支持TLSreturn ['status'=>false,'msg'=>$return];}fputs($this->sock,base64_encode($this->smtpUsername).$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='334'){//不支持TLSreturn ['status'=>false,'msg'=>$return];}fputs($this->sock,base64_encode($this->smtpPassword).$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='235'){//账号密码认证不成功return ['status'=>false,'msg'=>'账号密码认证不成功'];}return ['status'=>true];}/*** 设置邮件发送人和收件人*** */protected function smtpHeader(){fputs($this->sock,'mail from:<'.$this->from.'>'.$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='250'){//发送不成功return ['status'=>false,'msg'=>'发件人邮箱发送不成功'];}fputs($this->sock,'rcpt to:<'.$this->to.'>'.$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='250'){//发送不成功return ['status'=>false,'msg'=>'收件人邮箱发送不成功'];}return ['status'=>true];}/*** 设置邮件正文*** */protected function smtpBody(){fputs($this->sock,'data'.$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='354'){//发送不成功return ['status'=>false,'msg'=>'正文发送不成功'];}fputs($this->sock,'Return-path:<'.$this->from.'>'.$this->CRLF);fputs($this->sock,'Date:'.date('r').$this->CRLF);fputs($this->sock,'From:<'.$this->from.'>'.$this->CRLF);fputs($this->sock,'MIME-Version:1.0'.$this->CRLF);fputs($this->sock,'Subject:=?UTF-8?B?'.base64_encode(trim($this->title)).'?= '.$this->CRLF);fputs($this->sock,'To:<'.$this->to.'>'.$this->CRLF);if($this->attachment){//有附件$this->file_name=basename($this->attachment);$this->file_ext=$this->mb_pathinfo($this->file_name, PATHINFO_EXTENSION);$this->file_type=$this->_mime_types($this->file_ext);$boundary=$this->generateId();fputs($this->sock,'Content-type: multipart/mixed; boundary="'.$boundary.'"'.$this->CRLF.$this->CRLF);fputs($this->sock,'This is a multi-part message in MIME format.'.$this->CRLF);fputs($this->sock,'--'.$boundary.$this->CRLF);fputs($this->sock,'Content-type:text/plain; charset=UTF-8'.$this->CRLF);fputs($this->sock,'Content-Transfer-Encoding:base64'.$this->CRLF.$this->CRLF);fputs($this->sock,base64_encode($this->content).$this->CRLF.$this->CRLF);//附件fputs($this->sock,'--'.$boundary.$this->CRLF);fputs($this->sock,'Content-type:'.$this->file_type.'; name==?UTF-8?B?'.base64_encode($this->file_name).'?='.$this->CRLF);fputs($this->sock,'Content-Transfer-Encoding:base64'.$this->CRLF);fputs($this->sock,'Content-Disposition: attachment; filename==?UTF-8?B?'.base64_encode($this->file_name).'?='.$this->CRLF.$this->CRLF);$file_string=chunk_split(base64_encode(file_get_contents($this->attachment)),76,$this->CRLF);fputs($this->sock,$file_string.$this->CRLF);fputs($this->sock,'--'.$boundary.$this->CRLF);}else{//没附件fputs($this->sock,'Content-Type:text/html; charset=UTF-8; format=flowed'.$this->CRLF);fputs($this->sock,'Content-Transfer-Encoding:base64'.$this->CRLF.$this->CRLF);fputs($this->sock,base64_encode($this->content).$this->CRLF.$this->CRLF);}//结束符号 换行+制表+.+换行+制表fputs($this->sock,'.'.$this->CRLF);$return=fread($this->sock,512);if(substr($return,0,3)!='250'){//发送不成功return ['status'=>false,'msg'=>'正文发送不成功'];}return ['status'=>true];}protected function mb_pathinfo($path, $options = null){$ret = ['dirname' => '', 'basename' => '', 'extension' => '', 'filename' => ''];$pathinfo = [];if (preg_match('#^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$#im', $path, $pathinfo)) {if (array_key_exists(1, $pathinfo)) {$ret['dirname'] = $pathinfo[1];}if (array_key_exists(2, $pathinfo)) {$ret['basename'] = $pathinfo[2];}if (array_key_exists(5, $pathinfo)) {$ret['extension'] = $pathinfo[5];}if (array_key_exists(3, $pathinfo)) {$ret['filename'] = $pathinfo[3];}}switch ($options) {case PATHINFO_DIRNAME:case 'dirname':return $ret['dirname'];case PATHINFO_BASENAME:case 'basename':return $ret['basename'];case PATHINFO_EXTENSION:case 'extension':return $ret['extension'];case PATHINFO_FILENAME:case 'filename':return $ret['filename'];default:return $ret;}}/*** 根据后缀判断mime type* @param $ext 后缀** */protected function _mime_types($ext = ''){$mimes = ['xl' => 'application/excel','js' => 'application/javascript','hqx' => 'application/mac-binhex40','cpt' => 'application/mac-compactpro','bin' => 'application/macbinary','doc' => 'application/msword','word' => 'application/msword','xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet','xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template','potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template','ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow','pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation','sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide','docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document','dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template','xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12','xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12','class' => 'application/octet-stream','dll' => 'application/octet-stream','dms' => 'application/octet-stream','exe' => 'application/octet-stream','lha' => 'application/octet-stream','lzh' => 'application/octet-stream','psd' => 'application/octet-stream','sea' => 'application/octet-stream','so' => 'application/octet-stream','oda' => 'application/oda','pdf' => 'application/pdf','ai' => 'application/postscript','eps' => 'application/postscript','ps' => 'application/postscript','smi' => 'application/smil','smil' => 'application/smil','mif' => 'application/vnd.mif','xls' => 'application/vnd.ms-excel','ppt' => 'application/vnd.ms-powerpoint','wbxml' => 'application/vnd.wap.wbxml','wmlc' => 'application/vnd.wap.wmlc','dcr' => 'application/x-director','dir' => 'application/x-director','dxr' => 'application/x-director','dvi' => 'application/x-dvi','gtar' => 'application/x-gtar','php3' => 'application/x-httpd-php','php4' => 'application/x-httpd-php','php' => 'application/x-httpd-php','phtml' => 'application/x-httpd-php','phps' => 'application/x-httpd-php-source','swf' => 'application/x-shockwave-flash','sit' => 'application/x-stuffit','tar' => 'application/x-tar','tgz' => 'application/x-tar','xht' => 'application/xhtml+xml','xhtml' => 'application/xhtml+xml','zip' => 'application/zip','mid' => 'audio/midi','midi' => 'audio/midi','mp2' => 'audio/mpeg','mp3' => 'audio/mpeg','m4a' => 'audio/mp4','mpga' => 'audio/mpeg','aif' => 'audio/x-aiff','aifc' => 'audio/x-aiff','aiff' => 'audio/x-aiff','ram' => 'audio/x-pn-realaudio','rm' => 'audio/x-pn-realaudio','rpm' => 'audio/x-pn-realaudio-plugin','ra' => 'audio/x-realaudio','wav' => 'audio/x-wav','mka' => 'audio/x-matroska','bmp' => 'image/bmp','gif' => 'image/gif','jpeg' => 'image/jpeg','jpe' => 'image/jpeg','jpg' => 'image/jpeg','png' => 'image/png','tiff' => 'image/tiff','tif' => 'image/tiff','webp' => 'image/webp','heif' => 'image/heif','heifs' => 'image/heif-sequence','heic' => 'image/heic','heics' => 'image/heic-sequence','eml' => 'message/rfc822','css' => 'text/css','html' => 'text/html','htm' => 'text/html','shtml' => 'text/html','log' => 'text/plain','text' => 'text/plain','txt' => 'text/plain','rtx' => 'text/richtext','rtf' => 'text/rtf','vcf' => 'text/vcard','vcard' => 'text/vcard','ics' => 'text/calendar','xml' => 'text/xml','xsl' => 'text/xml','wmv' => 'video/x-ms-wmv','mpeg' => 'video/mpeg','mpe' => 'video/mpeg','mpg' => 'video/mpeg','mp4' => 'video/mp4','m4v' => 'video/mp4','mov' => 'video/quicktime','qt' => 'video/quicktime','rv' => 'video/vnd.rn-realvideo','avi' => 'video/x-msvideo','movie' => 'video/x-sgi-movie','webm' => 'video/webm','mkv' => 'video/x-matroska',];$ext = strtolower($ext);if (array_key_exists($ext, $mimes)) {return $mimes[$ext];}return 'application/octet-stream';}/*** 生成随机字符串 用于有附件时 邮件boundary 区分多个部分*** */protected function generateId(){$len = 32; //256 bitsif(function_exists('random_bytes')){$bytes = random_bytes($len);}else if(function_exists('openssl_random_pseudo_bytes')) {$bytes = openssl_random_pseudo_bytes($len);}else{$bytes = hash('sha256', uniqid((string) mt_rand(), true), true);}return 'b1_'.str_replace(['=', '+', '/'], '', base64_encode(hash('sha256', $bytes, true)));}/***断开smtp服务器连接 释放句柄*** */protected function close(){if($this->sock!==null){if($this->connectSMTP){fputs($this->sock,'QUIT'.$this->CRLF);if(substr(fread($this->sock,512),0,3)!='221'){//发送不成功return ['status'=>false,'msg'=>'退出指令发送失败'];}}if(is_resource($this->sock)){fclose($this->sock);}}return ['status'=>true];}/*** 析构函数 断开连接***/public function __destruct(){$this->close();}
}
?>

PHP使用socks5代理发送邮件相关推荐

  1. javamail通过代理发送邮件

    我们是没办法使用javamail通过一般的代理服务器发送邮件的,比如下面的代码是没有效果的: Properties props = System.getProperties();props.setPr ...

  2. 穿透Socks5 代理的UDP编程

    网络编程中,对于数据传输实时性要求较高的场合,大家都会选择UDP来作为数据传输协议,在TCP/IP协议族中UDP协议较TCP协议需要的网络系统资源更少.然而在企业应用中,由于网络安全原因等会导致除了特 ...

  3. #架构#重新设计socks5代理代码框架

    之前写过socks5代理,具体请看这篇文章. 在写任何代码代码之前,一直认为只有设计好了相应的数据结构,才能写好好的算法和框架.从前面的代码来看,对socks5协议的数据结构定义还算不错,具有很好的可 ...

  4. Socks代理是什么?PC端怎么使用Socks5代理?

    之前给大家介绍过代理IP是什么以及它的作用.代理服务器英文全称是Proxy Server,其功能就是代理网络用户去取得网络信息,形象的说:它是网络信息的中转站.最常用的代理莫过于HTTP代理与Sock ...

  5. socks5代理IP的几种测试工具

    socks5代理IP和HTTP代理存在着一定的区别,它们的使用网络协议存在区别,在使用方式上也存在区别,HTTP代理IP可以通过浏览器设置代理进行测试,而socks5代理IP却不能直接通过浏览器设置代 ...

  6. 使用Socks5代理加速爬虫访问的方法

    在进行网络爬虫开发的过程中,我们常常需要使用代理来模拟不同地区.不同网络环境的访问情况.而Socks5代理相比HTTP代理,更具有一些优势,例如可以实现UDP流量的转发,支持用户名密码认证等功能.本文 ...

  7. 如何设置SOCKS5代理?最全方法汇总!

    很多情况下我们都会使用到SOCKS5代理,例如设置QQ以及YY语音等等.设置网络代理对于网络冲浪的人们也是家常便饭的操作了.但不同的软件或浏览器使用代理,其设置方法是不一样的.那能不能同时使用代理软件 ...

  8. Socks5代理Socks5 Proxy

    Socks5代理Socks5 Proxy Socks5代理是基于Socks协议的一种代理模式.其中,5表示该协议的版本号.它可以让局域网的计算机通过socks5代理服务器,访问外网的内容.由于它工作在 ...

  9. nps+Proxifier搭建socks5代理隧道进行内网穿透

    目录 一.实验环境搭建 二.nps 服务端配置 客户端配置 将npc注册到系统服务 三.Proxifiers使用 在渗透过程中,我们需要快速实现内网穿透,从而绕过网络访问限制,直接从外网来访问内网 正 ...

最新文章

  1. Eclipse中配置Tomcat
  2. 通过poi的XSSF实现生成excel文件
  3. 数据结构之 顺序栈、共享栈、链栈
  4. STM32之DAC原理
  5. Sublime Text2 中文乱码
  6. python socket发送16进制数据_python socket以16进制的数据进行传递与解析
  7. python 读取pdf 两栏_python 读取pdf
  8. 正反斜杠的区别_电脑中的正斜杠(/)与反斜杠(\)的区别
  9. Redis数据类型(上)
  10. 算法笔记 --- 布隆过滤器
  11. 数据库中数据数据初始化的好处
  12. Java自学如何找工作?
  13. 设计一个简单的家乡网站
  14. 计算机音乐蜗牛与黄鹂鸟,音乐教材《蜗牛与黄鹂鸟》教案
  15. win10状态栏卡死,屏幕正常
  16. datatable 摧毁_我们快速的生活方式将使假新闻的发展摧毁我们。
  17. 攻防世界——web高手进阶区题解
  18. greenDao小坑一个
  19. 绘制地铁线路html,基于HTML5技术绘制上海地铁图
  20. Android TCP socket通信

热门文章

  1. 有关tty hangup
  2. bug记录-socket hang up
  3. python yield 与 yield from
  4. [NCTF 2018]签到题
  5. 按摩肺经,补足肺气眠自安
  6. 设计不会崩溃的健康码系统
  7. JavaScript遍历数组和对象
  8. Linux下Socket编程之TCP原理
  9. nginx实现https转发
  10. setClickable,setEnabled,setFocusable 的区别