后续有空再完善抓图程序,挺有趣的东西
2016-07-08 12:44
441 查看
#include <iostream> #include <iosfwd> #include <fstream> #include <regex> #include <string> #include <winsock2.h> #include <map> #include <queue> //v1.0使用socket实现最简单的http协议访问,其中http协议直接写, // 初步了解了http协议的构成和简单实现 //v2.0添加stl库中queue和map,并用遍历实现搜索所有相关网页,正则表达式匹配,并用socket下载所有图片 //v3.0实现多线程,读html和写图片两个线程 // 读html进程主要操作html队列pop,申请html的socket,读html内容,匹配html和图片并分别放入队列 // 写图片进程主要操作图片队列pop,申请图片socket,打开图片文件,写图片 //v4.0读写进程有互斥关系,对于写日志文件互斥,还有对于socket的访问返回结果互斥锁 // 如果下载gif动态图,使用上述方式经常阻塞,考虑增加多个线程分别下载图片 using namespace std; SOCKET sock; SOCKET sockMap1,sockMap2,sockMap3,sockMap4; //测试主机和端口 const char *testHostName="www.qxmuye.com"; const short testPort=80; const string testPortChar="80"; //vector<string> vectormapurl; //vector<string> vectorhtmlurl; queue<string> queueHtmlUrl; queue<string> queueMapUrl; map<string,int> mapMapUrl; int mapUrlInt; map<string,int> mapHtmlUrl; int htmlUrlInt; string mapType=".gif"; //定义一个互斥锁 pthread_mutex_t mutex; int fileNameInt1,fileNameInt2,fileNameInt3,fileNameInt4; //去字符串头尾空 string& trim(string &str) { if(str.empty()) { return str; } str.erase(0,str.find_first_not_of(" ")); str.erase(str.find_last_not_of(" ")+1); return str; } //发送http请求包 bool sendHttpQuery(string sendQueryStr){ int n=0; //初始化socket sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { cout << "建立socket失败! 错误码: " << WSAGetLastError() << endl; return false; } sockaddr_in sa = { AF_INET }; n = bind(sock, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "bind函数失败! 错误码: " << WSAGetLastError() << endl; return false; } struct hostent *p = gethostbyname(testHostName); if (p == NULL) { cout << "主机无法解析出ip! 错误吗: " << WSAGetLastError() << endl; return false; } sa.sin_port = htons(testPort); memcpy(&sa.sin_addr, p->h_addr, 4); //连接 n = connect(sock, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "connect函数失败! 错误码: " << WSAGetLastError() << endl; return false; } //按照http送GET请求 //cout<<"发送http请求:"+sendQueryStr<<endl; if (SOCKET_ERROR == send(sock, sendQueryStr.c_str(), sendQueryStr.size(), 0)) { cout << "send error! 错误码: " << WSAGetLastError() << endl; closesocket(sock); return false; } return true; } //发送图片请求包1 bool sendMapQuery1(string sendQueryStr){ int n=0; //初始化socket sockMap1 = socket(AF_INET, SOCK_STREAM, 0); if (sockMap1 == INVALID_SOCKET) { cout << "建立socket失败! 错误码: " << WSAGetLastError() << endl; return false; } sockaddr_in sa = { AF_INET }; n = bind(sockMap1, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "bind函数失败! 错误码: " << WSAGetLastError() << endl; return false; } struct hostent *p = gethostbyname(testHostName); if (p == NULL) { 4000 cout << "主机无法解析出ip! 错误吗: " << WSAGetLastError() << endl; return false; } sa.sin_port = htons(80); memcpy(&sa.sin_addr, p->h_addr, 4); //连接 n = connect(sockMap1, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "connect函数失败! 错误码: " << WSAGetLastError() << endl; return false; } //按照http送GET请求 cout<<"发送http请求:"+sendQueryStr<<endl; if (SOCKET_ERROR == send(sockMap1, sendQueryStr.c_str(), sendQueryStr.size(), 0)) { cout << "send error! 错误码: " << WSAGetLastError() << endl; closesocket(sockMap1); return false; } return true; } //发送图片请求包2 bool sendMapQuery2(string sendQueryStr){ int n=0; //初始化socket sockMap2 = socket(AF_INET, SOCK_STREAM, 0); if (sockMap2 == INVALID_SOCKET) { cout << "建立socket失败! 错误码: " << WSAGetLastError() << endl; return false; } sockaddr_in sa = { AF_INET }; n = bind(sockMap2, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "bind函数失败! 错误码: " << WSAGetLastError() << endl; return false; } struct hostent *p = gethostbyname(testHostName); if (p == NULL) { cout << "主机无法解析出ip! 错误吗: " << WSAGetLastError() << endl; return false; } sa.sin_port = htons(80); memcpy(&sa.sin_addr, p->h_addr, 4); //连接 n = connect(sockMap2, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "connect函数失败! 错误码: " << WSAGetLastError() << endl; return false; } //按照http送GET请求 cout<<"发送http请求:"+sendQueryStr<<endl; if (SOCKET_ERROR == send(sockMap2, sendQueryStr.c_str(), sendQueryStr.size(), 0)) { cout << "send error! 错误码: " << WSAGetLastError() << endl; closesocket(sockMap2); return false; } return true; } //发送图片请求包3 bool sendMapQuery3(string sendQueryStr){ int n=0; //初始化socket sockMap3 = socket(AF_INET, SOCK_STREAM, 0); if (sockMap3 == INVALID_SOCKET) { cout << "建立socket失败! 错误码: " << WSAGetLastError() << endl; return false; } sockaddr_in sa = { AF_INET }; n = bind(sockMap3, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "bind函数失败! 错误码: " << WSAGetLastError() << endl; return false; } struct hostent *p = gethostbyname(testHostName); if (p == NULL) { cout << "主机无法解析出ip! 错误吗: " << WSAGetLastError() << endl; return false; } sa.sin_port = htons(80); memcpy(&sa.sin_addr, p->h_addr, 4); //连接 n = connect(sockMap3, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "connect函数失败! 错误码: " << WSAGetLastError() << endl; return false; } //按照http送GET请求 cout<<"发送http请求:"+sendQueryStr<<endl; if (SOCKET_ERROR == send(sockMap3, sendQueryStr.c_str(), sendQueryStr.size(), 0)) { cout << "send error! 错误码: " << WSAGetLastError() << endl; closesocket(sockMap3); return false; } return true; } //发送图片请求包4 bool sendMapQuery4(string sendQueryStr){ int n=0; //初始化socket sockMap4 = socket(AF_INET, SOCK_STREAM, 0); if (sockMap4 == INVALID_SOCKET) { cout << "建立socket失败! 错误码: " << WSAGetLastError() << endl; return false; } sockaddr_in sa = { AF_INET }; n = bind(sockMap4, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "bind函数失败! 错误码: " << WSAGetLastError() << endl; return false; } struct hostent *p = gethostbyname(testHostName); if (p == NULL) { cout << "主机无法解析出ip! 错误吗: " << WSAGetLastError() << endl; return false; } sa.sin_port = htons(80); memcpy(&sa.sin_addr, p->h_addr, 4); //连接 n = connect(sockMap4, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "connect函数失败! 错误码: " << WSAGetLastError() << endl; return false; } //按照http送GET请求 cout<<"发送http请求:"+sendQueryStr<<endl; if (SOCKET_ERROR == send(sockMap4, sendQueryStr.c_str(), sendQueryStr.size(), 0)) { cout << "send error! 错误码: " << WSAGetLastError() << endl; closesocket(sockMap4); return false; } return true; } //从html中找出图片的url,分辨其唯一性(使用Map),并放入queue中 void getMapUrl(string &htmlContent){ smatch mat; //cout<<"图片匹配!"<<endl; regex pattern("data-original=\"([^ ]*?\.gif)\""); string::const_iterator stringStart = htmlContent.begin(); string::const_iterator stringEnd = htmlContent.end(); while (regex_search(stringStart,stringEnd, mat, pattern)) { string msg(mat[1].first, mat[1].second); //判断msg所在的url是否已遍历过 if(mapMapUrl.find(msg)==mapMapUrl.end()){ //cout<<"插入图片map库:"+msg<<endl; mapMapUrl.insert(pair<string, int>(msg,mapUrlInt)); //如果未遍历过,push到队列中 cout<<"插入图片队列:"+msg<<endl; queueMapUrl.push(msg); mapUrlInt++; } stringStart = mat[0].second; } smatch mat1; regex pattern1("src=\"([^ ]*?\.gif)\""); stringStart = htmlContent.begin(); stringEnd = htmlContent.end(); while (regex_search(stringStart,stringEnd, mat1, pattern1)) { string msg(mat1[1].first, mat1[1].second); //判断msg所在的url是否已遍历过 if(mapMapUrl.find(msg)==mapMapUrl.end()){ //cout<<"插入图片map库:"+msg<<endl; mapMapUrl.insert(pair<string, int>(msg,mapUrlInt)); //如果未遍历过,push到队列中 cout<<"插入图片队列:"+msg<<endl; queueMapUrl.push(msg); mapUrlInt++; } stringStart = mat1[0].second; } } //从html中找出html的url,分辨其唯一性(使用Map),并放入queue中 void getHtmlUrl(string &htmlContent){ smatch mat; //cout<<"html匹配!"<<endl; regex pattern("href=\"/([^ ]*?)\""); string::const_iterator stringStart = htmlContent.begin(); string::const_iterator stringEnd = htmlContent.end(); //pair<map<string,int>::iterator, bool> insertPair; while (regex_search(stringStart,stringEnd, mat, pattern)) { string msg(mat[1].first, mat[1].second); //判断msg所在的url是否已遍历过 if(mapHtmlUrl.find(msg)==mapHtmlUrl.end()){ // cout<<msg<<endl; if(trim(msg)!=""){ //cout<<"插入Html的map库:"+msg<<endl; mapHtmlUrl.insert(pair<string, int>(msg,htmlUrlInt)); //如果未遍历过,push到队列中 cout<<"插入Html的队列:"+msg<<endl; queueHtmlUrl.push(msg); htmlUrlInt++; } } stringStart = mat[0].second; } smatch mat1; //cout<<"html匹配!"<<endl; regex pattern1("href=\"([^ ]*?)\""); stringStart = htmlContent.begin(); stringEnd = htmlContent.end(); while (regex_search(stringStart,stringEnd, mat1, pattern1)) { string msg(mat1[1].first, mat1[1].second); //判断msg所在的url是否已遍历过 if(mapHtmlUrl.find(msg)==mapHtmlUrl.end()){ // cout<<msg<<endl; if(trim(msg)!=""){ // cout<<"插入Html的map库:"+msg<<endl; mapHtmlUrl.insert(pair<string, int>(msg,htmlUrlInt)); //如果未遍历过,push到队列中 cout<<"插入Html的队列:"+msg<<endl; queueHtmlUrl.push(msg); htmlUrlInt++; } } stringStart = mat1[0].second; } } //写图片文件 void *writeMapFile1Thread(void *ptr){ int n=0; char buf[1024]; memset(buf, 0, sizeof(buf)); fstream fileTmp; while(!queueMapUrl.empty()){ char *fileNameChar; sprintf(fileNameChar,"%d",fileNameInt1); //打开文档,当文档不存在时会无法打开,需要再看看原因 fileTmp.open("D:\\testmap\\1_"+(string)fileNameChar+mapType ,ios::out|ios::binary); cout << " 文档打开 D:\\testmap\\1_"+(string)fileNameChar << endl; if(!fileTmp.is_open()){ cout << " 文档打开失败! D:\\testmap\\1_"+(string)fileNameChar << endl; } //互斥锁锁定 pthread_mutex_lock(&mutex); string mapUrlStr; //得到图片的url mapUrlStr=queueMapUrl.front(); queueMapUrl.pop(); //线程互斥锁打开 pthread_mutex_unlock(&mutex); cout << " 图片队列退出: "+mapUrlStr << endl; string getRequestStr="GET "+mapUrlStr+" HTTP/1.1\r\nHost:"+(string)testHostName+":"+testPortChar+"\r\nConnection:Close\r\n\r\n"; //互斥锁锁定 //pthread_mutex_lock(&mutex); if(sendMapQuery1(getRequestStr)){ cout<<"开始写图文件!"<<endl; //接收返回的jpg文件 n = recv(sockMap1, buf, sizeof(buf)-1, 0); //过滤掉前面的字符 char *cpos = strstr(buf, "\r\n\r\n"); fileTmp.write(cpos + strlen("\r\n\r\n"), n - (cpos - buf) - strlen("\r\n\r\n")); while ((n = recv(sockMap1, buf, sizeof(buf)-1, 0)) > 0) { fileTmp.write(buf, n); } }else{ cout<<"图片http请求失败!"<<endl; } //线程互斥锁打开 //pthread_mutex_unlock(&mutex); cout<<"写图文件完成退出!"<<endl; fileNameInt1++; fileTmp.close(); } } //写图片文件2 void *writeMapFile2Thread(void *ptr){ int n=0; char buf[1024]; memset(buf, 0, sizeof(buf)); fstream fileTmp; while(!queueMapUrl.empty()){ char *fileNameChar; sprintf(fileNameChar,"%d",fileNameInt2); //打开文档,当文档不存在时会无法打开,需要再看看原因 fileTmp.open("D:\\testmap\\2_"+(string)fileNameChar+mapType ,ios::out|ios::binary); cout << " 文档打开 D:\\testmap\\2_"+(string)fileNameChar << endl; if(!fileTmp.is_open()){ cout << " 文档打开失败! D:\\testmap\\2_"+(string)fileNameChar << endl; } //互斥锁锁定 pthread_mutex_lock(&mutex); string mapUrlStr; //得到图片的url mapUrlStr=queueMapUrl.front(); queueMapUrl.pop(); //线程互斥锁打开 pthread_mutex_unlock(&mutex); cout << " 图片队列退出: "+mapUrlStr << endl; string getRequestStr="GET "+mapUrlStr+" HTTP/1.1\r\nHost:"+(string)testHostName+":"+testPortChar+"\r\nConnection:Close\r\n\r\n"; //互斥锁锁定 //pthread_mutex_lock(&mutex); if(sendMapQuery2(getRequestStr)){ cout<<"开始写图文件!"<<endl; //接收返回的jpg文件 n = recv(sockMap2, buf, sizeof(buf)-1, 0); //过滤掉前面的字符 char *cpos = strstr(buf, "\r\n\r\n"); fileTmp.write(cpos + strlen("\r\n\r\n"), n - (cpos - buf) - strlen("\r\n\r\n")); while ((n = recv(sockMap2, buf, sizeof(buf)-1, 0)) > 0) { fileTmp.write(buf, n); } }else{ cout<<"图片http请求失败!"<<endl; } //线程互斥锁打开 //pthread_mutex_unlock(&mutex); cout<<"写图文件完成退出!"<<endl; fileNameInt2++; fileTmp.close(); } } //写图片文件3 void *writeMapFile3Thread(void *ptr){ int n=0; char buf[1024]; memset(buf, 0, sizeof(buf)); fstream fileTmp; while(!queueMapUrl.empty()){ char *fileNameChar; sprintf(fileNameChar,"%d",fileNameInt3); //打开文档,当文档不存在时会无法打开,需要再看看原因 fileTmp.open("D:\\testmap\\3_"+(string)fileNameChar+mapType ,ios::out|ios::binary); cout << " 文档打开 D:\\testmap\\3_"+(string)fileNameChar << endl; if(!fileTmp.is_open()){ cout << " 文档打开失败! D:\\testmap\\3_"+(string)fileNameChar << endl; } //互斥锁锁定 pthread_mutex_lock(&mutex); string mapUrlStr; //得到图片的url mapUrlStr=queueMapUrl.front(); queueMapUrl.pop(); //线程互斥锁打开 pthread_mutex_unlock(&mutex); cout << " 图片队列退出: "+mapUrlStr << endl; string getRequestStr="GET "+mapUrlStr+" HTTP/1.1\r\nHost:"+(string)testHostName+":"+testPortChar+"\r\nConnection:Close\r\n\r\n"; if(sendMapQuery3(getRequestStr)){ cout<<"开始写图文件!"<<endl; //接收返回的jpg文件 n = recv(sockMap3, buf, sizeof(buf)-1, 0); //过滤掉前面的字符 char *cpos = strstr(buf, "\r\n\r\n"); fileTmp.write(cpos + strlen("\r\n\r\n"), n - (cpos - buf) - strlen("\r\n\r\n")); while ((n = recv(sockMap3, buf, sizeof(buf)-1, 0)) > 0) { fileTmp.write(buf, n); } }else{ cout<<"图片http请求失败!"<<endl; } cout<<"写图文件完成退出!"<<endl; fileNameInt3++; fileTmp.close(); } } //写图片文件4 void *writeMapFile4Thread(void *ptr){ int n=0; char buf[1024]; memset(buf, 0, sizeof(buf)); fstream fileTmp; while(!queueMapUrl.empty()){ char *fileNameChar; sprintf(fileNameChar,"%d",fileNameInt4); //打开文档,当文档不存在时会无法打开,需要再看看原因 fileTmp.open("D:\\testmap\\4_"+(string)fileNameChar+mapType ,ios::out|ios::binary); cout << " 文档打开 D:\\testmap\\4_"+(string)fileNameChar << endl; if(!fileTmp.is_open()){ cout << " 文档打开失败! D:\\testmap\\4_"+(string)fileNameChar << endl; } //互斥锁锁定 pthread_mutex_lock(&mutex); string mapUrlStr; //得到图片的url mapUrlStr=queueMapUrl.front(); queueMapUrl.pop(); //线程互斥锁打开 pthread_mutex_unlock(&mutex); cout << " 图片队列退出: "+mapUrlStr << endl; string getRequestStr="GET "+mapUrlStr+" HTTP/1.1\r\nHost:"+(string)testHostName+":"+testPortChar+"\r\nConnection:Close\r\n\r\n"; //互斥锁锁定 //pthread_mutex_lock(&mutex); if(sendMapQuery4(getRequestStr)){ cout<<"开始写图文件!"<<endl; //接收返回的jpg文件 n = recv(sockMap4, buf, sizeof(buf)-1, 0); //过滤掉前面的字符 char *cpos = strstr(buf, "\r\n\r\n"); fileTmp.write(cpos + strlen("\r\n\r\n"), n - (cpos - buf) - strlen("\r\n\r\n")); while ((n = recv(sockMap4, buf, sizeof(buf)-1, 0)) > 0) { fileTmp.write(buf, n); } }else{ cout<<"图片http请求失败!"<<endl; } //线程互斥锁打开 //pthread_mutex_unlock(&mutex); cout<<"写图文件完成退出!"<<endl; fileNameInt4++; fileTmp.close(); } } //读取返回的html内容,识别html和jpg,并分别加入到html和jpg的queue中 void *readHtmlContenThread(void *ptr){ int n=0; char buf[1024]; memset(buf, 0, sizeof(buf)); string htmlUrlStr; while(!queueHtmlUrl.empty()){ //得到图片的url htmlUrlStr=queueHtmlUrl.front(); queueHtmlUrl.pop(); //cout<<"出队列:"+htmlUrlStr<<endl; //string reqInfo = "GET /thread-551469-1.html HTTP/1.1\r\nHost:bbs.51cto.com:80\r\nConnection:Close\r\n\r\n"; string getRequestStr="GET "+htmlUrlStr+" HTTP/1.1\r\nHost:"+(string)testHostName+":"+testPortChar+"\r\nConnection:Close\r\n\r\n"; if(trim(htmlUrlStr)==""){ cout<<"请求html内容为空!"<<endl; //return; } //线程互斥锁锁定 //pthread_mutex_lock(&mutex); //cout<<"请求html内容:"+getRequestStr<<endl; if(sendHttpQuery(getRequestStr)){ //接收返回的jpg文件 n = recv(sock, buf, sizeof(buf)-1, 0); //cout<<buf <<endl; //过滤掉前面的字符 char *cpos = strstr(buf, "\r\n\r\n"); while ((n = recv(sock, buf, sizeof(buf)-1, 0)) > 0) { //filecontent.write(buf, n); string tmpbuf=buf; getHtmlUrl(tmpbuf); getMapUrl(tmpbuf); //cout<<cpos<<endl; } } //线程互斥锁打开 //pthread_mutex_unlock(&mutex); } } int main() { int n; char buf[1024]; memset(buf, 0, sizeof(buf)); //fstream file; WORD version(0); WSADATA wsadata; int socket_return(0); version = MAKEWORD(2,0); //socket通讯之前的初始化网络接口 socket_return = WSAStartup(version,&wsadata); if (socket_return != 0) { return 0; } fileNameInt1=0; fileNameInt2=0; fileNameInt3=0; fileNameInt4=0; pthread_mutex_init(&mutex,NULL); string strFirst="GET /article/dtt/ HTTP/1.1\r\nHost:www.qxmuye.com:80\r\nConnection:Close\r\n\r\n"; //发送http请求 if(!sendHttpQuery(strFirst)){ cout<<" http 请求发送失败! "<<endl; return 0; } cout<<" http 请求发送成功! "<<endl; n = recv(sock, buf, sizeof(buf)-1, 0); //strstr返回子串首次出现的地址,返回到char *类型中就是返回了首次出现的地址后的整个字符串 //利用strstr过滤掉响应消息的报文头:将\r\n\r\n加响应数据保存到*cpos,cpos是buf中第一次出现\r\n\r\n的地址 //将cpos+\r\n\r\n来去掉*cpos中的\r\n\r\n,放入文件中 //长度参数用接收到的字节数减去(两个地址直接的差)再减去\r\n\r\n,必须保证recv返回的是字节数,指针相减的差是字节数,strlen返回的也是字节数 // while ((n = recv(sock, buf, sizeof(buf)-1, 0)) > 0) { string tmpbuf=buf; getHtmlUrl(tmpbuf); getMapUrl(tmpbuf); } //当图片队列和html队列不为空时 //取html队列信息,发送socket的http请求报文,返回html内容字符串,解析html内容字符串 //将得到的html访问地址,加入到html队列中,将得到的jpg访问地址,加入到jpg队列中 //取jpg队列信息,发送socket的http请求报文,接收返回报文并写入本地文件 pthread_t testThreadGetHtml; int ret1= pthread_create(&testThreadGetHtml,NULL,readHtmlContenThread,NULL); if(ret1){ cout<<"创建读取html内容线程失败!"<<endl; return 1; } //Sleep(3000); cout<<"创建写图片文件线程1开始!"<<endl; pthread_t testthreadWrite1Map; int ret2= pthread_create(&testthreadWrite1Map,NULL,writeMapFile1Thread,NULL); if(ret2){ cout<<"创建写图片文件线程1失败!"<<endl; return 1; } //Sleep(3000); pthread_t testthreadWrite2Map; int ret3= pthread_create(&testthreadWrite2Map,NULL,writeMapFile2Thread,NULL); if(ret3){ cout<<"创建写图片文件线程2失败!"<<endl; return 1; } //Sleep(3000); pthread_t testthreadWrite3Map; int ret4= pthread_create(&testthreadWrite3Map,NULL,writeMapFile3Thread,NULL); if(ret4){ cout<<"创建写图片文件线程3失败!"<<endl; return 1; } //Sleep(3000); pthread_t testthreadWrite4Map; int ret5= pthread_create(&testthreadWrite4Map,NULL,writeMapFile4Thread,NULL); if(ret5){ cout<<"创建写图片文件线程4失败!"<<endl; return 1; } pthread_join(testThreadGetHtml,NULL); pthread_join(testthreadWrite1Map,NULL); pthread_join(testthreadWrite2Map,NULL); pthread_join(testthreadWrite3Map,NULL); pthread_join(testthreadWrite4Map,NULL); return 0; }
相关文章推荐
- java-模拟tomcat服务器
- Linux socket 初步
- 使用C++实现JNI接口需要注意的事项
- Python3写爬虫(四)多线程实现数据爬取
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- java socket 注意的地方
- java socket 注意的地方
- share_ptr的几个注意点
- C#实现多线程的同步方法实例分析
- C#基于socket模拟http请求的方法
- Lua中调用C++函数示例
- 浅谈chuck-lua中的多线程
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C#简单多线程同步和优先权用法实例
- 简单的Ruby中的Socket编程教程
- C#多线程学习之(四)使用线程池进行多线程的自动管理
- Socket不能选择本地IP连接问题如何解决
- C#之Socket操作类实例解析