手把手教你用C++ 写ACM自动刷题神器(冲入HDU首页)

少年,作为苦练ACM,通宵刷题的你 是不是想着有一天能够荣登各大OJ榜首,俯瞰芸芸众生,唔....要做到这件事情可是需要一定天赋的哦!

博主本身也搞过一段时间的acm,对刷题深有感触,不信可以去看我博客的acm题解(哈哈)。

不过,先给各位辛苦刷题的ACMer赔个不是,毕竟这是很投机的一种方式,仅供娱乐,还请各位见谅!

受学长的启蒙,打算自己做一个使用C++语言完成的自动刷题神器,也可以叫自动AC机(什么?ac自动机...吓尿),先来看一下成果:

(注:这是第一次刷完后的排名,后来对代码进行了很大的优化,但是由于时间关系,没有再刷一遍,否则肯定进入前十!)


第17名是我,AC率还算不错吧,但是我优化之后的肯定比这个高!

好了,扯淡完毕,下面进入正文,先来说一下整体思路


1)使用socket编程模拟HTTP协议GET请求向服务器发送页面请求

2)借助搜索引擎找到相关题目的代码(一般csdn的居多)

3)使用正则表达式解析HTML代码获取博客连接,紧接着从博客中解析出 题目的代码

4)对代码进行编码转换的处理,模仿HTTP协议的POST请求向服务器提交代码

5)解析提交后返回的State页面,提取最终的结果(是否Accepted)、耗时和空间占用。

6)将刷题过程存储至SQL Server数据库,供以后的数据分析。


是不是感觉很简单的样子,让我们一步一步来!


(一)使用socket编程模拟HTTP协议GET请求向服务器发送页面请求

我们在baidu中搜索关键字,点击按钮,服务器会返回我们一个页面,这件事情使用程序该如何实现呢?

答案就是我们使用Socket编程通过bind(),connect(),send(),recv()这些函数建立与服务器的连接。这些知识就不再这里展开了,读者可以自行baidu或者参考我的Linux网络编程专栏。 接下来我们想:点击按钮的过程发生了什么,我们使用send()需要将什么信息发送至服务器,这里就要涉及到HTTP协议的GET请求。

我们只需要实现GET的请求头即可(可以通过chrome按F12来查看),注意和正文之间有一个空行,即/r/n 

//向服务器发送GET请求 
	string  reqInfo = "GET " + (string)othPath + " HTTP/1.1\r\nHost: " + (string)host + "\r\nConnection:Close\r\n\r\n";
	if (SOCKET_ERROR == send(sock, reqInfo.c_str(), reqInfo.size(), 0))
	{
		cout << "send error! 错误码: " << WSAGetLastError() << endl;
		closesocket(sock);
	}
(二)借助搜索引擎获取csdn博客链接

一开始的时候我想利用百度搜索引擎,但是发现返回到HTML页面中根本无法找出csdn博客的链接特征,后来发现,原来是baidu为了避免爬虫爬取进行了加密处理,如下图:

注意左下角是第一个csdn博客的连接....坑了我一段时间。

后来发现360搜索没有加密,所以那就用360吧。。提取出来放入vector保存,然后使用C++11的正则表达式解析出csdn博客的地址。

void regexGetcom(string &allHtml) //提取网页中的csdn博客的url  
{
	blogUrl.clear();
	smatch mat;
	regex pattern("href=\"(http://blog.csdn[^\\s\"]+)\"");
	
	string::const_iterator start = allHtml.begin();
	string::const_iterator end = allHtml.end();
	while (regex_search(start, end, mat, pattern))
	{
		string msg(mat[1].first, mat[1].second);
		blogUrl.push_back(msg);
		start = mat[0].second;
	}
}

(三)从HTML中解析出代码


注意代码一般由#include开始,结束的位置是</textarea>或者</pre>,我们利用这个特征进行提取。

void GetCode(string &allHtml)
{
	CodeHtml = "";
	int pos = allHtml.find("#include");
	if (pos != string::npos)
	{
		for (int i = pos; i < allHtml.length(); i++)
		{
			
			if ((allHtml[i] == '<'&&allHtml[i + 1] == '/'&&allHtml[i + 2] == 't'&&allHtml[i + 3] == 'e'&&allHtml[i + 4] == 'x'&&allHtml[i + 5] == 't') || (allHtml[i] == '<'&&allHtml[i + 1] == '/'&&allHtml[i + 2] == 'p'&&allHtml[i + 3] == 'r'&&allHtml[i + 4] == 'e'&&allHtml[i + 5] == '>'))
			{
				return ;
			}
			CodeHtml += allHtml[i];
		}
	}
	else
	{
		cout << "未找到合适的代码!" << endl;
		return;
	}
	
}

(四)对代码进行编码转换的处理,模仿HTTP协议的POST请求向服务器提交代码

我们可以看到上面的代码并不是解析出来就能用的,还包含有&lt,&gt等HTML的元素,并且还有汉字转码的问题需要我们需要处理。POST的时候,还需要考虑HTTP编码,

将空格回车等转换为十六进制发送提交,不说了,直接看代码:

string ReplaceDiv(string &CodeHtml)
{
	string ans;
	for (int i = 0; i < CodeHtml.length(); i++)
	{
		if (CodeHtml[i] == '&'&&CodeHtml[i + 1] == 'l'&&CodeHtml[i + 2] == 't'&&CodeHtml[i + 3] == ';')
		{
			ans += '<';
			i += 3;
		}
		else if (CodeHtml[i] == '&'&&CodeHtml[i + 1] == 'g'&&CodeHtml[i + 2] == 't'&&CodeHtml[i + 3] == ';')
		{
			ans += '>';
			i += 3;
		}
		else if (CodeHtml[i] == '/'&&CodeHtml[i + 1] == 'n')
		{
			ans += "\\n";
			i +=1;
		}
		else if (CodeHtml[i] == '&'&&CodeHtml[i + 1] == 'a'&&CodeHtml[i + 2] == 'm'&&CodeHtml[i + 3] == 'p'&&CodeHtml[i + 4] == ';')
		{
			ans += '&';
			i += 4;
		}
		else if (CodeHtml[i] == '&'&&CodeHtml[i + 1] == 'q'&&CodeHtml[i + 2] == 'u'&&CodeHtml[i + 3] == 'o'&&CodeHtml[i + 4] == 't'&&CodeHtml[i + 5] == ';')
		{
			ans += '\"';
			i += 5;
		}
		else if (CodeHtml[i] == '&'&&CodeHtml[i + 1] == 'n'&&CodeHtml[i + 2] == 'b'&&CodeHtml[i + 3] == 's'&&CodeHtml[i + 4] == 'p'&&CodeHtml[i + 5] == ';')
		{
			ans += ' ';
			i += 5;
		}
		else if (CodeHtml[i] == '&'&&CodeHtml[i + 1] == '#'&&CodeHtml[i + 2] == '4'&&CodeHtml[i + 3] == '3'&&CodeHtml[i + 4] == ';')
		{
			ans += '+';
			i += 4;
		}
		else if (CodeHtml[i] == '&'&&CodeHtml[i + 1] == '#'&&CodeHtml[i + 2] == '3'&&CodeHtml[i + 3] == '9'&&CodeHtml[i + 4] == ';')
		{
			ans += '\'';
			i += 4;
		}
		else
			ans += CodeHtml[i];
	}
	return ans;
}

string ASCtoHex(int num) //十进制转换成十六进制
{
	char str[] = "0123456789ABCDEF";
	int temp=num;
	string ans;
	while (temp)
	{
		ans += str[temp % 16];
		temp /= 16;
	}
	ans += '%';
	reverse(ans.begin(), ans.end());
	return ans;
}
string GetRescode(string &CodeHtml)
{
	ResCode = "";
	for (int i = 0; i < CodeHtml.length(); i++)
	{
			//if (!isdigit(unsigned(CodeHtml[i])) && !isalpha(unsigned(CodeHtml[i])))
			if ((CodeHtml[i] >= 0 && CodeHtml[i] < 48) || (CodeHtml[i]>57 && CodeHtml[i]<65) || (CodeHtml[i]>90 && CodeHtml[i]<97) || (CodeHtml[i]>122 & CodeHtml[i] <= 127))
			{
				//if (CodeHtml[i] == '\r' && (i + 1) < CodeHtml.length() && CodeHtml[i + 1] == '\n')
				//if (CodeHtml[i] == '\r')
				//{
				//	ResCode += "++%0D";
				//
				//}
				//else if (CodeHtml[i] == '\n')
				if (CodeHtml[i] == '\n')
				{
					ResCode += "%0D%0A";
				}
				else if (CodeHtml[i] == '.' || CodeHtml[i] == '-' || CodeHtml[i] == '*')
					ResCode += CodeHtml[i];

				/*if (CodeHtml[i] == 10)
					ResCode += "%0D%0A";
					*/
				/*else if (CodeHtml[i] >= 0xB0 && (i + 1)<CodeHtml.length()&&CodeHtml[i + 1] >= 0xA1)//判断汉字
				{
				i++;
				ResCode += CodeHtml[i];
				ResCode += CodeHtml[i + 1];
				}*/
				else
				{
					string cur = ASCtoHex(CodeHtml[i]);
					if (cur == "%9")
						ResCode += "++++";
					else if (cur == "%20")
						ResCode += '+';
					else if (cur == "%D")
						ResCode += "++";
					else
						ResCode += cur;
				}

			}
			else
				ResCode += CodeHtml[i];

		}
		
	return ResCode;
//UTF-8到GB2312的转换
char* U2G(const char* utf8)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
	len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len + 1];
	memset(str, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
	if (wstr) delete[] wstr;
	return str;
}

POST:注意头信息要全,并且Cookie要写你自己的,一旦浏览器关闭就会失效,要重置

string  Typee = "\r\nContent-Type: application/x-www-form-urlencoded";
	string ConLen = "\r\nContent-Length: ";
	_itoa(ProblemID, s, 10);

	//string ElseInfo = "\r\nCache-Control: max-age=0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8O\r\nOrigin: http://acm.hdu.edu.cn\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36\r\nReferer: http://acm.hdu.edu.cn/submit.php?pid=1003\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: zh-CN,zh;q=0.8";
	string ElseInfo = "\r\nCache-Control: max-age=0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8O\r\nOrigin: http://acm.hdu.edu.cn\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36\r\nReferer: http://acm.hdu.edu.cn/submit.php?pid=";
	ElseInfo = ElseInfo+ (string)s + "\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: zh-CN,zh;q=0.8";
	//向服务器发送POST请求 
	
	string HeaderP="check=0&problemid="+(string)s;
	HeaderP += "&language=2&usercode=";
	
	ResCode = HeaderP + ResCode;
	char s[300];
	_itoa( ResCode.length(), s, 10);  /??????
	string Cookie = "exesubmitlang=2; PHPSESSID=8qdqoujc8ptncdb518cksqr687; CNZZDATA1254072405=385429082-1445151305-http%253A%252F%252Facm.hdu.edu.cn%252F%7C1446089001";
	string  reqInfo = "POST " + (string)othPath + " HTTP/1.1\r\nHost: " + (string)host + ElseInfo+ Typee + ConLen + (string)s + "\r\nCookie: " + Cookie + "\r\nConnection:Close\r\n\r\n" + ResCode;

	if (SOCKET_ERROR == send(sock, reqInfo.c_str(), reqInfo.size(), 0))
	{
		cout << "send error! 错误码: " << WSAGetLastError() << endl;
		closesocket(sock);
	}

(五)解析提交后返回的State页面,提取最终的结果(是否Accepted)、耗时和空间占用

这个就比较简单了,数据分析,可能实现都不一样,我是先定位的题号:

void GetResult(string &allHtml,int Prob)  //解析出state.php中的结果,空间,时间
{
	 StateAns="";
	 StateSapce="";
	 StateTime="";
	char d[200];
	_itoa(ProblemID, d, 10);
	strcat(d, "</a>");
	int pos = allHtml.find((string)d);
	int Mpos = pos;
	int Tpos;
	if (Mpos == string::npos)
		return;
	else
	{
		Mpos += 17;
		while (1)
		{
			if (allHtml[Mpos] == '<')
			{
				Tpos = Mpos;
				break;
			}
			StateSapce += allHtml[Mpos];
			Mpos++;
		}
		cout << "使用的空间大小为:" << StateSapce << endl;

	}
	Tpos += 9;
	while (1)
	{
		if (allHtml[Tpos] == '<')
			break;
		StateTime += allHtml[Tpos];
		Tpos++;
	}
	cout << "使用的时间为:" << StateTime << endl;

	if (pos == string::npos)
		return;
	else
	{
		pos = pos - 52;
		int begin;
		while (1)
		{
			if (allHtml[pos] == '>')
			{
				begin = pos;
				break;
			}
			pos--;
		}
	
		for (int i = begin + 1;allHtml[i]!='<';i++)
		{
			StateAns += allHtml[i];
		}
	}
	cout << "最终的state界面的答案是:" << "---------------::::::" << StateAns << endl;


}

(六)将刷题过程存储至SQL Server数据库,供以后的数据分析

要点就是C++使用ado连接SQL Server数据库

CoInitialize(NULL);//初始化Com库
	_ConnectionPtr pMyConnect = NULL;//这是个对象指针,关于对象指针的内容可以百度一下,不过不理解也就算了
	HRESULT hr = pMyConnect.CreateInstance(__uuidof(Connection));
	//将对象指针实例化
	if (FAILED(hr))
	{
		cout << "_ConnectionPtr对象指针实例化失败!" << endl;
		return 0;
	}
	_bstr_t strConnect="Driver={sql server};server=Tach-PC\\SQLEXPRESS;uid=tach1;pwd=123456;database=ProblemSolved";  //SQLSERVER
	//这是连接到SQL SERVER数据库的连接字符串,其中的参数要自己改
	try{
		pMyConnect->Open(strConnect, "", "", NULL); 
	}//连接到数据库,要捕捉异常
	catch (_com_error &e){
		cout << "连接数据库异常!" << endl;
		cout << e.ErrorMessage() << endl;
	}
注意将上面的server名字,uid和pwd改为你自己的。

下图的Queuing请无视,因为我为了速度并没有Sleep(),页面还没有显示出结果,对,我比较懒==


好啦,到这里就大功告成啦!别刷太快哦,貌似被hdu封了一次IP。。。。。(囧)

最后项目的完整源码在我的Github,欢迎大家fork!

有疑问或者优化请留言或者 通过邮箱联系我,联系方式在博客的左上角,希望给大家学习网络编程带来帮助!





  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
第 1章 概述 1 1.1 网络编程相关的基本概念 1 1.1.1 网络编程与进程通信 1 1.1.2 Internet中网间进程的标识 3 1.1.3 网络协议的特征 7 1.2 三类网络编程 10 1.2.1 基于TCP/IP协议栈的网络编程 10 1.2.2 基于WWW应用的网络编程 10 1.2.3 基于.NET框架的Web Services网络编程 10 1.3 客户机/服务器交互模式 13 1.3.1 网络应用软件的地位和功能 13 1.3.2 客户机/服务器模式 14 1.3.3 客户机与服务器的特性 15 1.3.4 容易混淆的术语 16 1.3.5 客户机与服务器的通信过程 16 1.3.6 网络协议与C/S模式的关系 17 1.3.7 错综复杂的C/S交互 17 1.3.8 服务器如何同时为多个客户机服务 18 1.3.9 标识一个特定服务 20 1.4 P2P模式 21 1.4.1 P2P技术的兴起 21 1.4.2 P2P的定义和特征 21 1.4.3 P2P的发展 22 1.4.4 P2P的关键技术 22 1.4.5 P2P系统的应用与前景 22 习题 23 第 2章 套接字网络编程基础 24 2.1 套接字网络编程接口的产生与发展 24 2.1.1 问题的提出 24 2.1.2 套接字编程接口起源于UNIX操作系统 25 2.1.3 套接字编程接口在Windows和Linux操作系统中得到继承和发展 25 2.1.4 套接字编程接口的两种实现方式 25 2.1.5 套接字通信与UNIX操作系统的输入/输出的关系 26 2.2 套接字编程的基本概念 27 2.2.1 什么是套接字 27 2.2.2 套接字的特点 28 2.2.3 套接字的应用场合 30 2.2.4 套接字使用的数据类型和相关的问题 30 2.3 面向连接的套接字编程 32 2.3.1 可靠的传输控制协议 32 2.3.2 套接字的工作过程 33 2.3.3 面向连接的套接字编程实例 34 2.3.4 进程的阻塞问题和对策 40 2.4 无连接的套接字编程 43 2.4.1 高效的用户数据报协议 43 2.4.2 无连接的套接字编程的两种模式 43 2.4.3 数据报套接字的对等模式编程实例 45 2.5 原始套接字 47 2.5.1 原始套接字的创建 47 2.5.2 原始套接字的使用 48 2.5.3 原始套接字应用实例 49 习题 51 第3章 WinSock编程 53 3.1 WinSock概述 53 3.2 WinSock库函数 55 3.2.1 WinSock的注册与注销 55 3.2.2 WinSock的错误处理函数 58 3.2.3 主要的WinSock函数 61 3.2.4 WinSock的辅助函数 74 3.2.5 WinSock的信息查询函数 77 3.2.6 WSAAsyncGetXByY类型的扩展函数 79 3.3 网络应用程序的运行环境 82 习题 84 第4章 MFC编程 85 4.1 MFC概述 85 4.1.1 MFC是一个编程框架 85 4.1.2 典型的MDI应用程序的构成 87 4.2 MFC和Win32 89 4.2.1 MFC对象和Windows对象的关系 89 4.2.2 几个主要的类 91 4.3 CObject类 95 4.3.1 CObject类的定义 95 4.3.2 CObject类的特性 96 4.4 消息映射的实现 98 4.5 MFC对象的创建 102 4.5.1 MFC对象的关系 102 4.5.2 MFC提供的接口 104 4.5.3 MFC对象的创建过程 104 4.6 应用程序的退出 107 习题 107 第5章 MFC WinSock类的 编程 109 5.1 CAsyncSocket类 110 5.1.1 使用CAsyncSocket类的一般步骤 110 5.1.2 创建CAsyncSocket类对象 111 5.1.3 关于CAsyncSocket类可以接受并处理的消息事件 112 5.1.4 客户端套接字对象请求连接到服务器端套接字对象 114 5.1.5 服务器接收客户机的连接请求 115 5.1.6 发送与接收流式数据 116 5.1.7 关闭套接字 118 5.1.8 错误处理 118 5.1.9 其他成员函数 119 5.2 CSocket类 120 5.2.1 创建CSocket对象 120 5.2.2 建立连接 120 5.2.3 发送和接收数据 120 5.2.4 CSocket类、CArchive类和CSocketFile类 121 5.2.5 关闭套接字和清除相关的对象 122 5.3 CSocket类的编程模型 122 5.4 用CAsyncSocket类实现聊天室程序 123 5.4.1 实现目标 123 5.4.2 创建客户端应用程序 124 5.4.3 客户端程序的类与消息驱动 134 5.4.4 客户端程序主要功能的代码和分析 135 5.4.5 创建服务器端程序 142 5.4.6 服务器端程序的流程和消息驱动 144 5.4.7 点对点交谈的服务器端程序主要功能的代码和分析 145 5.5 用CSocket类实现聊天室程序 151 5.5.1 聊天室程序的功能 151 5.5.2 创建聊天室的服务器端程序 151 5.5.3 聊天室服务器端程序的主要实现代码和分析 154 5.5.4 创建聊天室的客户端程序 162 5.5.5 聊天室客户端程序的主要实现代码和分析 163 习题 170 实验 170 第6章 WinInet编程 172 6.1 MFC WinInet类 172 6.1.1 概述 172 6.1.2 MFC WinInet所包含的类 173 6.1.3 使用WinInet类编程的一般步骤 174 6.1.4 创建CInternetSession类对象 175 6.1.5 查询或设置Internet请求选项 176 6.1.6 创建连接类对象 177 6.1.7 使用文件检索类 178 6.1.8 重载OnStatusCallback函数 179 6.1.9 创建并使用网络文件类对象 180 6.1.10 CInternteException类 183 6.2 用MFC WinInet类实现FTP客户端 183 6.2.1 程序要实现的功能 183 6.2.2 创建应用程序的过程 184 习题 186 实验 187 第7章 WinSock的多线程 编程 188 7.1 WinSock为什么需要多线程编程 188 7.1.1 WinSock的两种I/O模式 188 7.1.2 两种模式的优缺点及解决方法 189 7.2 Win32操作系统下的多进程多线程机制 189 7.2.1 Win32 OS是单用户多任务的操作系统 189 7.2.2 Win32 OS是支持多线程的操作系统 190 7.2.3 多线程机制在网络编程中的应用 191 7.3 VC++对多线程网络编程的支持 192 7.3.1 MFC支持的两种线程 192 7.3.2 创建MFC的工作线程 193 7.3.3 创建并启动用户界面线程 195 7.3.4 终止线程 198 7.4 多线程FTP客户端实例 200 7.4.1 编线程函数 200 7.4.2 添加事件处理函数 206 习题 208 第8章 WinSock的I/O模型 209 8.1 select模型 210 8.2 WSAAsyncSelect异步I/O模型 212 8.3 WSAEventSelect事件选择模型 216 8.4 重叠I/O模型 221 8.4.1 重叠I/O模型的优点 221 8.4.2 重叠I/O模型的基本原理 221 8.4.3 重叠I/O模型的关键函数和数据结构 222 8.4.4 使用事件通知实现重叠模型的步骤 225 8.4.5 使用完成例程实现重叠模型的步骤 227 8.5 完成端口模型 229 8.5.1 什么是完成端口模型 229 8.5.2 使用完成端口模型的方法 230 习题 238 第9章 HTTP及编程 239 9.1 HTTP 239 9.1.1 HTTP的背景 239 9.1.2 HTTP的内容 240 9.1.3 HTTP消息的一般格式 242 9.1.4 HTTP请求的格式 243 9.1.5 HTTP响应的格式 245 9.1.6 访问认证 248 9.1.7 URL编码 249 9.1.8 HTTP的应用 250 9.2 利用CHtmlView类创建Web浏览器型的应用程序 250 9.2.1 CHtmlView类与WebBrowser控件 250 9.2.2 CHtmlView类的成员函数 251 9.2.3 创建一个Web浏览器型的应用程序的一般步骤 256 9.3 Web浏览器应用程序实例 261 9.3.1 程序实现的目标 261 9.3.2 创建实例程序 262 习题 265 实验 265 第 10章 电子邮件协议与编程 267 10.1 电子邮件系统的工作原理 267 10.1.1 电子邮件的特点 267 10.1.2 电子邮件系统的构成 267 10.1.3 电子邮件系统的实现 268 10.2 简单邮件传送协议 270 10.2.1 概述 270 10.2.2 SMTP客户机与SMTP服务器之间的会话 270 10.2.3 常用的SMTP命令 271 10.2.4 常用的SMTP响应码 273 10.2.5 SMTP的会话过程 274 10.2.6 使用WinSock来实现电子邮件客户机与服务器的会话 274 10.3 电子邮件信件结构详述 275 10.3.1 Internet文本信件的格式标准——RFC 822 275 10.3.2 信件的头部 276 10.3.3 构造和分析符合RFC 822标准的电子信件 281 10.4 MIME编码解码与发送附件 281 10.4.1 MIME概述 281 10.4.2 MIME定义的新的信头字段 282 10.4.3 MIME邮件的内容类型 283 10.4.4 MIME邮件的编码方式 292 10.5 POP3与接收电子邮件 294 10.5.1 POP3 294 10.5.2 POP3的会话过程 294 10.5.3 POP3会话的3个状态 295 10.5.4 POP3标准命令 296 10.5.5 接收电子邮件的一般步骤 298 10.6 接收电子邮件的程序实例 299 10.6.1 实例程序的目的和实现的技术要点 299 10.6.2 创建应用程序的过程 301 10.7 发送电子邮件的程序实例 302 10.7.1 实例程序的目的和实现的技术要点 302 10.7.2 创建应用程序的过程 303 习题 305 参考文献 307
linux C语言 网络编程教程及源码 一、网络应用层编程 1、Linux网络编程01——网络协议入门 2、Linux网络编程02——无连接和面向连接的区别 3、Linux网络编程03——字节序和地址转换 4、Linux网络编程04——套接字 5、Linux网络编程05——C/S与B/S架构的区别 6、Linux网络编程06——UDP协议编程 7、Linux网络编程07——广播 8、Linux网络编程08——多播 9、Linux网络编程09——TCP编程之客户端 10、Linux网络编程10——TCP编程之服务器 11、Linux网络编程11——tcp、udp迭代服务器 12、Linux网络编程12——tcp三次握手、四次挥手 13、Linux网络编程13——connect()、listen()和accept()三者之间的关系 14、Linux网络编程14——I/O复用之select详解 15、Linux网络编程15——I/O复用之poll详解 16、Linux网络编程16——I/O复用之epoll详解 17、Linux网络编程17——tcp并发服务器(多进程) 18、Linux网络编程18——tcp并发服务器(多线程) 19、Linux网络编程——tcp高效并发服务器(select实现) 20、Linux网络编程——tcp高效并发服务器(poll实现) 21、Linux网络编程——tcp高效并发服务器(epoll实现) 二、网络底层编程(黑客模式) 1、Linux网络编程1——啥叫原始套接字 2、Linux网络编程2——原始套接字编程 3、Linux网络编程3——原始套接字实例:MAC头分析 4、Linux网络编程4——原始套接字实例:MAC地址扫描器 5、Linux网络编程5——IP数据报格式详解 6、Linux网络编程6——TCP、UDP数据包格式详解 7、Linux网络编程7——原始套接字实例:发送UDP数据包 8、Linux网络编程8——libpcap详解 9、Linux网络编程9——libnet详解
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值