﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Dark Angle-最新评论</title><link>http://www.cppblog.com/niewenlong/CommentsRSS.aspx</link><description /><language>zh-cn</language><pubDate>Wed, 03 Dec 2008 08:05:57 GMT</pubDate><lastBuildDate>Wed, 03 Dec 2008 08:05:57 GMT</lastBuildDate><generator>cnblogs</generator><item><title>re: Mysql日期和时间函数不求人[未登录]</title><link>http://www.cppblog.com/niewenlong/archive/2008/11/27/58900.html#67971</link><dc:creator>王博炜</dc:creator><author>王博炜</author><pubDate>Thu, 27 Nov 2008 03:04:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/11/27/58900.html#67971</guid><description><![CDATA[好<img src ="http://www.cppblog.com/niewenlong/aggbug/67971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">王博炜</a> 2008-11-27 11:04 <a href="http://www.cppblog.com/niewenlong/archive/2008/11/27/58900.html#67971#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: DirectX与OpenGL方面的经典电子书下载 </title><link>http://www.cppblog.com/niewenlong/archive/2008/11/21/67465.html#67467</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Fri, 21 Nov 2008 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/11/21/67465.html#67467</guid><description><![CDATA[联系：QQ513306007，说清楚要用这本书，呵呵... ... <br>附其他的相关资料： <br>Game Developer Magazine 1994 - 2000年，共7年的游戏开发者杂志电子版（含源码） <br>Graphics Programming Black Book (by Michael Abrash).zip，图形编程黑书，Id software的Michael Abrash编著 <br>Game Programming Gems I.rar ，游戏编程精粹I、II（含源码） <br>Game Programming Gems II.rar <br>Graphics Gems I.rar ，图形学精粹I、II、III、IV、V <br>Graphics Gems II.rar <br>Graphics Gems III IBM.rar <br>Graphics Gems IV IBM.rar <br>Graphics Gems V.rar <br>Computer Graphics, C Version (2nd Ed.).rar ，计算机图形学C版（第二版） <br>half_life2_engine.zip ，半条命2游戏引擎源代码 <br>D3DTutorial10_Half-Life2_Shading.pdf ，半条命2游戏引擎光照分析 <br>Course.PTR.3D.Game.Engine.Programming.eBook-LinG.rar ，3D游戏引擎编程 <br>3D Game Engine Design.rar ，3D游戏引擎设计 <br>3D Game Engine Design source code.rar ，3D游戏引擎设计源代码 <br>3D.Game.Programming.All.In.One.zip ，3D游戏编程大全 <br>Game Design - Theory and Practice.rar ，游戏设计 - 理论与实践 <br>game.programming.all.in.one.zip ，游戏编程大全 <br>The Cg Tutorial - The Definitive Guide to Programmable Real-Time Graphics.rar ，CG指导 - 可编程实时图形权威指南 <br>Tricks Of The 3D Game Programming Gurus - Advanced 3D Graphics And Rasterization.rar ，3D游戏编程大师技巧 - 高级3D图形和光栅化 <br>Ultimate Game Design Building Game Worlds.rar ，终极游戏设计 - 创建游戏世界 <br>Core.Techniques.And.Algorithms.In.Game.Programming.rar ，核心技术和算法在游戏编程 <br>Simulating Humans.rar ，仿真人类 <br><br>3D Lighting - History, Concepts, and Techniques.rar ，3D光照 - 历史，概念和技术 <br>Lighting.Techniques.For.Real-Time.3D.Rendering.rar ，光照技术For实时3D渲染 <br>Vector.Game.Math.Processors.zip ，向量游戏数学处理器 <br>AI for Computer Games and Animation - A Cognitive Modeling Approach.rar ，AI（人工智能）for计算机游戏和动画 - 一个认知建模方案 <br>AI.Game.Development.Synthetic.Creatures.With.Learning.And.Reactive.Behaviors.rar ，AI游戏开发 - 合成生物With学习和反应举止 <br>AI.Techniques.for.Game.Programming.rar ，AI技术for游戏编程（含源码） <br>Ai.Game.Programming.Wisdom.rar ，AI游戏编程（代码） <br>Real_Time_Rendering.rar ，实时渲染 <br>special.effects.game.programming.rar ，特效（特殊效果）游戏编程（含源码） <br>Shaders.for.Game.Programmers.and.Artists.zip ，着色器for游戏开发者和艺术家 <br>Real-Time Shader Programming.rar ，实时着色器编程 <br>Wordware.Publishing.Advanced.Lighting.and.Materials.With.Shaders.rar ，高级光照和材质with着色器 <br>OReilly - Physics for Game Developers.rar ，物理for游戏开发者 <br><br>GPU Programming Guide.rar ，GPU编程指南 <br>Collision.Detection.pdf.rar ，碰撞检测 <br>Collision.Detection.-.Algorithms.and.Applications.rar ，碰撞检测 - 算法与应用 <br>focus.on.3D.terrain.zip ，游戏3D地形编程 <br>Focus.On.3D.Models.zip ，游戏3D模型编程 <br>Focus.On.2D.in.Direct3D.-.fly.pdf ，集中于Direct3D中的2D <br>Beginning.Game.Audio.Programming.rar ，开始游戏音频编程（含源码） <br>Internetworked.3D.Computer.Graphics.rar ，互连网间的3D计算机图形学 <br><br>Beginning.Math.and.Physics.For.Game.Programmers.zip ，开始数学和物理for游戏编程者（PDF版） <br>Beginning Math and Physics for Game Programmers[CHM].rar ，开始数学和物理for游戏编程者（CHM版） <br>3D.Math.Primer.for.graphics.and.game.development.zip ，3D数学初步for图形和游戏开发 <br>The art of computer game design.rar ，计算机游戏设计艺术 <br>Sams.Beginning.3D.Game.Programming.eBook-LiB.rar ，3D游戏编程入门 <br>MIT.Press.Rules.of.Play.Game.Design.Fundamentals.rar ，游戏设计基础 <br>design a pc game engine.rar ，设计一个PC游戏引擎 <br><br>Advanced Graphics Programming Techniques Using Opengl.rar ，高级图形编程技术用OpenGL <br>Real-time.Rendering.Tricks.and.Techniques.in.DirectX.rar ，DirectX实时渲染技巧与技术 <br>Real-Time Rendering Tricks and Techniques in DirectX(src).ZIP ，DirectX实时渲染技巧与技术（源代码） <br>Real Time 3D Terrain Engines Using C++ And Dx9.rar ，实时3D地形引擎用C++和Dx9 <br>MS.Press.-.Microsoft.DirectX.9.Programmable.Graphics.Pipeline.rar ，Microsoft DirectX9可编程图形管线 <br>Wordware.Publishing.OpenGL.Game.Development.eBook-YYePG.rar ，OpenGL游戏开发 <br>Beginning.OpenGL.Game.Programming.ebook.zip ，OpenGL游戏编程入门 <br>OpenGL.Programming.Guide.rar ，OpenGL编程指南 <br>Addison.Wesley.-.OpenGL.Programming.Guide.2nd.Edition.rar ，OpenGL编程指南（第二版） <br>Addison-Wesley,.OpenGL.Shading.Language.(2004).DDU.ShareConnector.rar ，OpenGL着色语言（2004） <br>Learn Vertex and Pixel Shader Programming With Directx 9.rar ，学习顶点和像素着色器编程用DirectX9 <br>Shaderx2 - Shader Programming Tips &amp; Tricks With Directx 9.rar ，Shaderx2 - 着色器编程提示与技巧With DirectX9 <br>ShaderX2 Introductions and Tutorials with DirectX9.rar ，ShaderX2介绍和指导With DirectX9 <br>Direct3D.ShaderX.-.Vertex.and.Pixel.Shader.Tips.and.Tricks.rar ，Direct3D.ShaderX - 顶点和像素着色器提示和技巧 <br>Advanced 3D Game Programming with DirectX 9.rar ，高级3D游戏编程用DirectX 9.0（含源码，CHM版） <br>Advanced 3D Game Programming with DirectX 9[PDF].rar ，高级3D游戏编程用DirectX 9.0（PDF版） <br>DirectX 3D Graphics Programming Bible.rar ，DirectX 3D图形编程宝典 <br>Introduction to 3D Game Programming with DirectX 9.0.rar ，介绍对3D游戏编程用DirectX9.0（含部分源代码） <br>Beginning.Direct3D.Game.Programming.rar ，Direct3D游戏编程入门 <br>Beginning.DirectX9.zip ，DirectX9入门 <br>Cutting Edge Direct 3D Programming.rar ，Cutting Edge（刀刃）Direct 3D编程 <br>Game.Scripting.Mastery.zip ，游戏描述语言掌握 <br>Data.Structures.for.Game.Programmers.rar ，数据结构for游戏编程者（含源码） <br>2_OpenGL.Extensions.-.Nvidia.rar ，OpenGL扩展（Nvidia） <br>Managed.DX.9.Kick.Start.Graphics.And.Game.Programming.rar ，DirectX9图形和游戏编程 <br>OpenGL.Reference.Manual.rar ，OpenGL参考手册 <br>OpenGL.Super.Bible.rar ，OpenGL超级宝典 <br><br>Tricks of the Windows Game Programming Gurus.rar ，Windows游戏编程大师技巧 <br>Tricks of Win Game Programming Gurus 2ed.rar ，Windows游戏编程大师技巧(第二版) <br>Game.Programming.Beginners.Guide.rar ，游戏编程初学者指南 <br>Chris_Crawford_on_Game_Design.rar ，Chris Crawford写的游戏设计书 <br><br>Advanced.Animation.with.DirectX.rar ，高级动画with DirectX（含源码） <br>Inside Direct3D.rar ，深入Direct3D <br>Direct3D_9_Basics.rar ，Direct3D 9基础 <br>Sams Teach Yourself DirectX 7 in 24 Hours.rar ，教你自己DirectX7在24小时 <br>Programming.Role.Playing.Games.with.DirectX.rar ，用DirectX编程RPG游戏（含源码） <br>Programming Multiplayer Games.rar ，编程多玩家游戏 <br>Net Game Programming With Directx 9.0.rar ，网络游戏编程with Directx 9.0 <br>Programming Linux Games.rar ，编程Linux游戏 <br>Developing Online Games - An Insiders Guide.rar ，开发在线游戏 - 一个权威人士的指导 <br>Game Coding Complete.rar ，游戏编码完全 <br>Strategy Game Programming with DirectX 9.0.rar ，策略游戏编程用DirectX9.0 <br>Strategy Game Programming with DirectX 9.0 Source Code.zip ，策略游戏编程用DirectX9.0（源代码） <br>Addison-Wesley - Software Engineering and Computer Games.rar ，软件工程和计算机游戏 <br>Artificial Intelligence and Software Engineering.rar ，AI和软件工程 <br>Game-Programming-OpenGL-C++.rar ，有关OpenGl和C++的一些资料 <br><br>GBA Programming Game Boy Advance The Unofficial Guide.rar ，GBA编程非官方指南 <br>Palm.OS.Game.Programming.zip ，Palm掌上操作系统游戏编程 <br>Mac.Game.Programming.pdf ，苹果机游戏编程 <br>Premier.Press.J2ME.Game.Programming.rar ，J2ME游戏编程 <br>J2ME Game Development with MIDP2.rar ，J2ME游戏开发with MIDP2 <br>PHP.Game.Programming.zip ，PHP语言游戏编程 <br>Game.Programming.with.Python.Lua.And.Ruby.zip ，游戏编程用Python,Lua和Ruby语言 <br>Apress.dot.NET.Game.Programming.with.DirectX.9.0.eBook-KB.rar ，点NET游戏编程用DirectX9 <br>Wordware.Wireless.Game.Development.In.C.Cpp.With.BREW.chm ，无线游戏开发用C、C++ With BREW <br><br>DirectX9 User Interfaces Design and Implementation.rar ，DirectX9用户接口设计和实现 <br>Game.Interface.Design.rar ，游戏接口设计 <br><br><br>SAMS Teach Yourself Game Programming in 24 Hours.rar ，教你自己游戏编程在24小时 <br>C.Game.Programming.For.Dummies.2.rar ，C游戏编程傻瓜书2 <br>Beginners Guide to DarkBASIC Game Programming.rar ，初学者指南对DarkBASIC游戏编程 <br>Windows Graphics Programming Win32 GDI and DirectDraw.rar ，Windows图形编程 - Win32 GDI 和 DirectDraw <br>Game Programming Genesis.rar ，游戏编程起步 <br><br>2D.Artwork.and.3D.Modeling.for.Game.Artists.zip ，2D艺术品和3D建模for游戏艺术家 <br>Game.Art.for.Teens.pdf ，游戏艺术for青年人 <br><br>Game Development and Production.rar ，游戏开发和产品 <br>Game.Developers.Market.Guide.rar ，游戏开发者市场指南 <br><br><br>MIT.Press.A.History.Of.Modern.Computing.eBook-LiB.rar ，现代计算历史 <br>The C++ Programming Language NO.3 Edition.rar ，C++编程语言（第三版） <br>Computer Systems A Programmers Perspective.rar ，计算机系统 - 一个编程者的透视 <br>Intel Architecture Software Developer Manual.zip ，Intel架构软件开发者手册 <br>Intel Itanium Assembly Language Reference.rar ，Intel Itanium架构汇编语言参考 <br>Agile Software Development.rar ，灵活的软件开发 <br>Code Reading The Open Source Perspective.rar ，代码阅读与开放源透视 <br><br>ps2DevEnvironment.exe ，PS2开发环境 <br>doxygen-1.3.9.1-setup.exe ，一种文档自动生成软件 <br>wolf_source.exe ，wolf游戏（id software）源代码 <br>doom_src.zip ，doom游戏（id software）源代码 <br>q2src320.exe ，Quake2游戏（id software）源代码 <br>Q3A_TA_GameSource_127.exe ，QuakeIII（id software）游戏源代码 <br>Q3A_ToolSource.exe ，QuakeIII（id software）工具源代码 <br><img src ="http://www.cppblog.com/niewenlong/aggbug/67467.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-11-21 11:17 <a href="http://www.cppblog.com/niewenlong/archive/2008/11/21/67465.html#67467#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: http://evaphone.com/</title><link>http://www.cppblog.com/niewenlong/archive/2008/11/20/64074.html#67351</link><dc:creator>wenwen</dc:creator><author>wenwen</author><pubDate>Thu, 20 Nov 2008 00:50:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/11/20/64074.html#67351</guid><description><![CDATA[hao <img src ="http://www.cppblog.com/niewenlong/aggbug/67351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">wenwen</a> 2008-11-20 08:50 <a href="http://www.cppblog.com/niewenlong/archive/2008/11/20/64074.html#67351#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: vc模拟鼠标键盘操作实用类</title><link>http://www.cppblog.com/niewenlong/archive/2008/11/15/28382.html#66986</link><dc:creator>逍遥行</dc:creator><author>逍遥行</author><pubDate>Sat, 15 Nov 2008 05:58:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/11/15/28382.html#66986</guid><description><![CDATA[你好，能不能给我个demo，我是个初学者，不是很专业。<br><br>我的email：erej@163.com<img src ="http://www.cppblog.com/niewenlong/aggbug/66986.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">逍遥行</a> 2008-11-15 13:58 <a href="http://www.cppblog.com/niewenlong/archive/2008/11/15/28382.html#66986#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: 为SQLite数据库添加加密功能[未登录]</title><link>http://www.cppblog.com/niewenlong/archive/2008/11/03/25261.html#65854</link><dc:creator>我</dc:creator><author>我</author><pubDate>Mon, 03 Nov 2008 09:14:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/11/03/25261.html#65854</guid><description><![CDATA[楼主你是个好人中的好人<img src ="http://www.cppblog.com/niewenlong/aggbug/65854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">我</a> 2008-11-03 17:14 <a href="http://www.cppblog.com/niewenlong/archive/2008/11/03/25261.html#65854#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: 代理服务器代码</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64600</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Tue, 21 Oct 2008 03:35:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64600</guid><description><![CDATA[[转载]C语言写的Linux平台socks5代理程序<br>C语言写的Linux平台socks5代理程序<br><br>信息来源：邪恶八进制信息安全团队（www.eviloctal.com）<br><br>前几天MSN老上不去，我还以为是公司做了防火墙限制。于是把去年这个时候写得一个代理程序改了改，拿出来用。结果发现MSN是因为微软的问题，鄙视啊……<br>因为写得比较急，这个只支持TCP代理，UDP的我没写，因为MSN用不上。这个代码可以随意修改分发，不过最好能给我一份。<br><br>这是头文件： <br>///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br>// Socks5代理头文件，定义协议相关数据包结构<br>// 版本 0.1，作者 云舒<br>// 2007年1月9日凌晨1点15分，GF回家已经11天了。<br>// 2008年1月25日修改，今年GF一直在我身边，哈哈<br>//<br>// 参考：<br>// <a target="_new" href="<a target="_new" href="http://www.rfc-editor.org/rfc/rfc1928.txt">http://www.rfc-editor.org/rfc/rfc1928.txt</a>"><a target="_new" href="http://www.rfc-editor.org/rfc/rfc1928.txt">http://www.rfc-editor.org/rfc/rfc1928.txt</a></a><br>// <a target="_new" href="<a target="_new" href="http://www.rfc-editor.org/rfc/rfc1929.txt">http://www.rfc-editor.org/rfc/rfc1929.txt</a>"><a target="_new" href="http://www.rfc-editor.org/rfc/rfc1929.txt">http://www.rfc-editor.org/rfc/rfc1929.txt</a></a><br>///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br><br>#ifndef SOCKS5_H<br>#define SOCKS5_H<br><br>#define VERSION 0x05<br>#define CONNECT 0x01<br>#define IPV4 0x01<br>#define DOMAIN 0x03<br>#define IPV6 0x04<br><br>typedef struct _method_select_response // 协商方法服务器响应<br>{<br>char version; // 服务器支持的Socks版本，0x04或者0x05<br>char select_method;// 服务器选择的方法，0x00为匿名，0x02为密码认证<br>} METHOD_SELECT_RESPONSE;<br><br>typedef struct _method_select_request // 协商方法服务端请求<br>{<br>char version; // 客户端支持的版本，0x04或者0x05<br>char number_methods; // 客户端支持的方法的数量<br>char methods[255]; // 客户端支持的方法类型，最多255个，0x00为匿名，0x02为密码认证<br>} METHOD_SELECT_REQUEST;<br><br>typedef struct _AUTH_RESPONSE // 用户密码认证服务端响应<br>{<br>char version;// 版本，此处恒定为0x01<br>char result;// 服务端认证结果，0x00为成功，其他均为失败<br>} AUTH_RESPONSE;<br><br>typedef struct _AUTH_REQUEST //用户密码认证客户端请求<br>{<br>char version; // 版本，此处恒定为0x01<br>char name_len; // 第三个字段用户名的长度，一个字节，最长为0xff<br>char name[255]; // 用户名<br>char pwd_len;// 第四个字段密码的长度，一个字节，最长为0xff<br>char pwd[255]; // 密码<br>} AUTH_REQUEST;<br><br>typedef struct _SOCKS5_RESPONSE // 连接真实主机，Socks代理服务器响应<br>{<br>char version; // 服务器支持的Socks版本，0x04或者0x05<br>char reply; // 代理服务器连接真实主机的结果，0x00成功<br>char reserved; // 保留位，恒定位0x00<br>char address_type; // Socks代理服务器绑定的地址类型，IP V4为0x01,IP V6为0x04，域名为0x03 <br>char address_port[1]; // 如果address_type为域名，此处第一字节为域名长度，其后为域名本身，无0字符结尾,域名后为Socks代理服务器绑定端口<br>}SOCKS5_RESPONSE; <br><br>typedef struct _SOCKS5_REQUEST // 客户端请求连接真实主机<br>{<br>char version; // 客户端支持的Socks版本，0x04或者0x05<br>char cmd; // 客户端命令，CONNECT为0x01，BIND为0x02，UDP为0x03，一般为0x01<br>char reserved; // 保留位，恒定位0x00<br>char address_type; // 客户端请求的真实主机的地址类型，IP V4为0x00,IP V6为0x04，域名为 0x03 char address_port[1]; // 如果address_type为域名，此处第一字节为域名长度，其后为域名本身，无0字符结尾,域名后为真实主机绑定端口<br><br>}SOCKS5_REQUEST; <br>#endif <br>主程序来了： <br>///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br>// Socks5程序，只支持TCP代理<br>// 版本 0.1，作者 云舒<br>// 2007年1月9日凌晨1点15分，GF回家已经11天了。<br>// 2008年1月25日修改，今年GF一直在我身边，哈哈<br>//<br>// 参考：<br>// <a target="_new" href="<a target="_new" href="http://www.rfc-editor.org/rfc/rfc1928.txt">http://www.rfc-editor.org/rfc/rfc1928.txt</a>"><a target="_new" href="http://www.rfc-editor.org/rfc/rfc1928.txt">http://www.rfc-editor.org/rfc/rfc1928.txt</a></a><br>// <a target="_new" href="<a target="_new" href="http://www.rfc-editor.org/rfc/rfc1929.txt">http://www.rfc-editor.org/rfc/rfc1929.txt</a>"><a target="_new" href="http://www.rfc-editor.org/rfc/rfc1929.txt">http://www.rfc-editor.org/rfc/rfc1929.txt</a></a><br>//编译：<br>// gcc -o socks5 -O2 Socks5.c -lpthread( RedHat AS5测试 ）<br>///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br><br>#include &lt;stdio.h&gt;<br>#include &lt;netinet/in.h&gt;<br>#include &lt;netdb.h&gt;<br>#include &lt;sys/time.h&gt;<br>#include &lt;sys/types.h&gt;<br>#include &lt;unistd.h&gt;<br>#include &lt;stdlib.h&gt;<br>#include &lt;signal.h&gt;<br>#include &lt;pthread.h&gt;<br>#include &lt;errno.h&gt;<br>#include &lt;string.h&gt;<br>#include &lt;sys/socket.h&gt;<br>#include &lt;arpa/inet.h&gt;<br><br>#include &quot;Socks5.h&quot;<br><br>#define MAX_USER 10<br>#define BUFF_SIZE 1024<br><br>#define AUTH_CODE 0x02<br><br>#define TIME_OUT 6000000<br><br>#define USER_NAME &quot;yunshu&quot;<br>#define PASS_WORD &quot;ph4nt0m&quot;<br><br>// Select auth method, return 0 if success, -1 if failed<br>int SelectMethod( int sock )<br>{<br>char recv_buffer[BUFF_SIZE] = { 0 };<br>char reply_buffer[2] = { 0 };<br><br>METHOD_SELECT_REQUEST *method_request;<br>METHOD_SELECT_RESPONSE *method_response;<br><br>// recv METHOD_SELECT_REQUEST<br>int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );<br>if( ret &lt;= 0 )<br>{<br>perror( &quot;recv error&quot; );<br>close( sock );<br><br>return -1;<br>}<br><br>//printf( &quot;SelectMethod: recv %d bytes\n&quot;, ret );<br><br>// if client request a wrong version or a wrong number_method<br>method_request = (METHOD_SELECT_REQUEST *)recv_buffer;<br>method_response = (METHOD_SELECT_RESPONSE *)reply_buffer;<br><br>method_response-&gt;version = VERSION;<br><br>// if not socks5<br>if( (int)method_request-&gt;version != VERSION )<br>{<br>method_response-&gt;select_method = 0xff;<br><br>send( sock, method_response, sizeof(METHOD_SELECT_RESPONSE), 0 );<br>close( sock );<br><br>return -1;<br>}<br><br>method_response-&gt;select_method = AUTH_CODE;<br>if( -1 == send( sock, method_response, sizeof(METHOD_SELECT_RESPONSE), 0 ) )<br>{<br>close( sock );<br>return -1;<br>}<br><br>return 0;<br>}<br><br>// test password, return 0 for success.<br>int AuthPassword( int sock )<br>{<br>char recv_buffer[BUFF_SIZE] = { 0 };<br>char reply_buffer[BUFF_SIZE] = { 0 };<br><br>AUTH_REQUEST *auth_request;<br>AUTH_RESPONSE *auth_response;<br><br>// auth username and password<br>int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );<br>if( ret &lt;= 0 )<br>{<br>perror( &quot;recv username and password error&quot; );<br>close( sock );<br>return -1;<br>}<br>//printf( &quot;AuthPass: recv %d bytes\n&quot;, ret );<br><br>auth_request = (AUTH_REQUEST *)recv_buffer;<br><br>memset( reply_buffer, 0, BUFF_SIZE );<br>auth_response = (AUTH_RESPONSE *)reply_buffer;<br>auth_response-&gt;version = 0x01;<br><br>char recv_name[256] = { 0 };<br>char recv_pass[256] = { 0 };<br><br>// auth_request-&gt;name_len is a char, max number is 0xff<br>char pwd_str[2] = { 0 };<br>strncpy( pwd_str, auth_request-&gt;name + auth_request-&gt;name_len, 1 );<br>int pwd_len = (int)pwd_str[0];<br><br>strncpy( recv_name, auth_request-&gt;name, auth_request-&gt;name_len );<br>strncpy( recv_pass, auth_request-&gt;name + auth_request-&gt;name_len + sizeof(auth_request-&gt;pwd_len), pwd_len );<br><br>//printf( &quot;username: %s\npassword: %s\n&quot;, recv_name, recv_pass );<br>// check username and password<br>if( (strncmp( recv_name, USER_NAME, strlen(USER_NAME) ) == 0) &amp;&amp;<br>(strncmp( recv_pass, PASS_WORD, strlen(PASS_WORD) ) == 0)<br>)<br>{<br>auth_response-&gt;result = 0x00;<br>if( -1 == send( sock, auth_response, sizeof(AUTH_RESPONSE), 0 ) )<br>{<br>close( sock );<br>return -1;<br>}<br>else<br>{<br>return 0;<br>}<br>}<br>else<br>{<br>auth_response-&gt;result = 0x01;<br>send( sock, auth_response, sizeof(AUTH_RESPONSE), 0 );<br><br>close( sock );<br>return -1;<br>}<br>}<br><br>// parse command, and try to connect real server.<br>// return socket for success, -1 for failed.<br>int ParseCommand( int sock )<br>{<br>char recv_buffer[BUFF_SIZE] = { 0 };<br>char reply_buffer[BUFF_SIZE] = { 0 };<br><br>SOCKS5_REQUEST *socks5_request;<br>SOCKS5_RESPONSE *socks5_response;<br><br>// recv command<br>int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );<br>if( ret &lt;= 0 )<br>{<br>perror( &quot;recv connect command error&quot; );<br><br>close( sock );<br>return -1;<br>}<br><br>socks5_request = (SOCKS5_REQUEST *)recv_buffer;<br>if( (socks5_request-&gt;version != VERSION) || (socks5_request-&gt;cmd != CONNECT) ||<br>(socks5_request-&gt;address_type == IPV6) )<br>{<br>//printf( &quot;connect command error.\n&quot; );<br>close( sock );<br>return -1;<br>}<br><br>// begain process connect request<br>struct sockaddr_in sin;<br><br>memset( (void *)&amp;sin, 0, sizeof(struct sockaddr_in) );<br>sin.sin_family = AF_INET;<br><br>// get real server&amp;#39;s ip address<br>if( socks5_request-&gt;address_type == IPV4 )<br>{<br>memcpy( &amp;sin.sin_addr.s_addr, &amp;socks5_request-&gt;address_type + sizeof(socks5_request-&gt;address_type) , 4 );<br>memcpy( &amp;sin.sin_port, &amp;socks5_request-&gt;address_type + sizeof(socks5_request-&gt;address_type) + 4, 2 );<br><br>//printf( &quot;Real Server: %s %d\n&quot;, inet_ntoa( sin.sin_addr ), ntohs( sin.sin_port ) );<br>}<br>else if( socks5_request-&gt;address_type == DOMAIN )<br>{<br>char domain_length = *(&amp;socks5_request-&gt;address_type + sizeof(socks5_request-&gt;address_type));<br>char target_domain[ 256] = { 0 };<br><br>strncpy( target_domain, &amp;socks5_request-&gt;address_type + 2, (unsigned int)domain_length );<br><br>//printf( &quot;target: %s\n&quot;, target_domain );<br><br>struct hostent *phost = gethostbyname( target_domain );<br>if( phost == NULL )<br>{<br>//printf( &quot;Resolve %s error!\n&quot; , target_domain );<br><br>close( sock );<br>return -1;<br>}<br>memcpy( &amp;sin.sin_addr , phost-&gt;h_addr_list[0] , phost-&gt;h_length );<br><br>memcpy( &amp;sin.sin_port, &amp;socks5_request-&gt;address_type + sizeof(socks5_request-&gt;address_type) +<br>sizeof(domain_length) + domain_length, 2 );<br>}<br><br>// try to connect to real server<br>int real_server_sock = socket( AF_INET, SOCK_STREAM, 0 );<br>if( real_server_sock &lt; 0 )<br>{<br>perror( &quot;Socket creation failed\n&quot;);<br><br>close( sock );<br>return -1;<br>}<br><br>memset( reply_buffer, 0, sizeof(BUFF_SIZE) );<br><br>socks5_response = (SOCKS5_RESPONSE *)reply_buffer;<br><br>socks5_response-&gt;version = VERSION;<br>socks5_response-&gt;reserved = 0x00;<br>socks5_response-&gt;address_type = 0x01;<br>memset( socks5_response + 4, 0 , 6 );<br><br>ret = connect( real_server_sock, (struct sockaddr *)&amp;sin, sizeof(struct sockaddr_in) );<br>if( ret == 0 )<br>{<br>socks5_response-&gt;reply = 0x00;<br>if( -1 == send( sock, socks5_response, 10, 0 ) )<br>{<br>close( sock );<br><br>return -1;<br>}<br>}<br>else<br>{<br>perror( &quot;Connect to real server error&quot; );<br>socks5_response-&gt;reply = 0x01;<br>send( sock, socks5_response, 10, 0 );<br><br>close( sock );<br>return -1;<br>}<br><br>return real_server_sock;<br>}<br><br>int ForwardData( int sock, int real_server_sock )<br>{<br>char recv_buffer[BUFF_SIZE] = { 0 };<br><br>fd_set fd_read;<br>struct timeval time_out;<br><br>time_out.tv_sec = 0;<br>time_out.tv_usec = TIME_OUT;<br><br>int ret = 0;<br><br>while( 1 )<br>{<br>FD_ZERO( &amp;fd_read );<br>FD_SET( sock, &amp;fd_read );<br>FD_SET( real_server_sock, &amp;fd_read );<br><br>ret = select( (sock &gt; real_server_sock ? sock : real_server_sock) + 1, &amp;fd_read, NULL, NULL, &amp;time_out );<br>if( -1 == ret )<br>{<br>perror( &quot;select socket error&quot; );<br>break;<br>}<br>else if( 0 == ret )<br>{<br>//perror( &quot;select time out&quot; );<br>continue;<br>}<br><br>//printf( &quot;[DEBUG] testing readable!\n&quot; );<br>if( FD_ISSET(sock, &amp;fd_read) )<br>{<br>//printf( &quot;client can read!\n&quot; );<br>memset( recv_buffer, 0, BUFF_SIZE );<br>ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );<br>if( ret &gt; 0 )<br>{<br>//printf( &quot;%s&quot;, recv_buffer );<br>//printf( &quot;recv %d bytes from client.\n&quot;, ret );<br>ret = send( real_server_sock, recv_buffer, ret, 0 );<br>if( ret == -1 )<br>{<br>perror( &quot;send data to real server error&quot; );<br>break;<br>}<br>//printf( &quot;send %d bytes to client!\n&quot;, ret );<br>}<br>else if( ret == 0 )<br>{<br>//printf( &quot;client close socket.\n&quot; );<br>break;<br>}<br>else<br>{<br>//perror( &quot;recv from client error&quot; );<br>break;<br>}<br>}<br><br>else if( FD_ISSET(real_server_sock, &amp;fd_read) )<br>{<br>//printf( &quot;real server can read!\n&quot; );<br>memset( recv_buffer, 0, BUFF_SIZE );<br>ret = recv( real_server_sock, recv_buffer, BUFF_SIZE, 0 );<br>if( ret &gt; 0 )<br>{<br>//printf( &quot;%s&quot;, recv_buffer );<br>//printf( &quot;recv %d bytes from real server.\n&quot;, ret );<br>ret = send( sock, recv_buffer, ret, 0 );<br>if( ret == -1 )<br>{<br>perror( &quot;send data to client error&quot; );<br>break;<br>}<br>}<br>else if( ret == 0 )<br>{<br>//printf( &quot;real server close socket.\n&quot; );<br>break;<br>}<br>else<br>{<br>perror( &quot;recv from real server error&quot; );<br>break;<br>}<br>}<br>}<br><br>return 0;<br>}<br><br>int Socks5( void *client_sock )<br>{<br>int sock = *(int *)client_sock;<br><br>if( SelectMethod( sock ) == -1 )<br>{<br>//printf( &quot;socks version error\n&quot; );<br>return -1;<br>}<br><br>if( AuthPassword( sock ) == -1 )<br>{<br>//printf( &quot;auth password error\n&quot; );<br>return -1;<br>}<br><br>int real_server_sock = ParseCommand( sock );<br>if( real_server_sock == -1 )<br>{<br>//printf( &quot;parse command error.\n&quot; );<br>return -1;<br>}<br><br>ForwardData( sock, real_server_sock );<br><br>close( sock );<br>close( real_server_sock );<br><br>return 0;<br>}<br><br>int main( int argc, char *argv[] )<br>{<br>if( argc != 2 )<br>{<br>printf( &quot;Socks5 proxy for test,code by YunShu\n&quot; );<br>printf( &quot;Usage: %s &lt;proxy_port&gt;\n&quot;, argv[0] );<br>printf( &quot;Options:\n&quot; );<br>printf( &quot; &lt;proxy_port&gt; ---which port of this proxy server will listen.\n&quot; );<br><br>return 1;<br>}<br><br>struct sockaddr_in sin;<br><br>memset( (void *)&amp;sin, 0, sizeof( struct sockaddr_in) );<br>sin.sin_family = AF_INET;<br>sin.sin_port = htons( atoi(argv[1]) );<br>sin.sin_addr.s_addr = htonl(INADDR_ANY);<br><br>int listen_sock = socket( AF_INET, SOCK_STREAM, 0 );<br>if( listen_sock &lt; 0 )<br>{<br>perror( &quot;Socket creation failed\n&quot;);<br>return -1;<br>}<br><br>int opt = SO_REUSEADDR;<br>setsockopt( listen_sock, SOL_SOCKET, SO_REUSEADDR, &amp;opt, sizeof(opt) );<br><br>if( bind( listen_sock, (struct sockaddr*)&amp;sin, sizeof(struct sockaddr_in) ) &lt; 0 )<br>{<br>perror( &quot;Bind error&quot; );<br>return -1;<br>}<br><br>if( listen( listen_sock, MAX_USER ) &lt; 0 )<br>{<br>perror( &quot;Listen error&quot; );<br>return -1;<br>}<br><br>struct sockaddr_in cin;<br>int client_sock;<br>int client_len = sizeof( struct sockaddr_in );<br><br>while( client_sock = accept( listen_sock, (struct sockaddr *)&amp;cin, (socklen_t *)&amp;client_len ) )<br>{<br>printf( &quot;Connected from %s, processing......\n&quot;, inet_ntoa( cin.sin_addr ) );<br><br>pthread_t work_thread;<br>if( pthread_create( &amp;work_thread, NULL, (void *)Socks5, (void *)&amp;client_sock ) )<br>{<br>perror( &quot;Create thread error...&quot; );<br>close( client_sock );<br>}<br>else<br>{<br>pthread_detach( work_thread );<br>}<br>}<br>} <img src ="http://www.cppblog.com/niewenlong/aggbug/64600.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-21 11:35 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64600#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: 代理服务器代码</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64564</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 20 Oct 2008 18:29:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64564</guid><description><![CDATA[关于通过http代理访问Internet<br>最近在网上查了一点关于通过Socket代理或者http代理访问internet的资料，国内的资料比较少，查到了一点英文资料，觉得讲得还不错。<br>When an HTTP connection is made through a proxy server the client (usually the browser) sends the request to the proxy. The proxy opens the connection to the destination, sends the request, receives the response and sends it back to the client. The HTTP protocol specifies a request method called CONNECT. The CONNECT method can be used by the client to inform the proxy server that a connection to some host on some port is required. The proxy server, if allows such connections, tries to connect to the destination address specified in the request header. If it the operation fails it sends back to the client a negative HTTP response and close the connection. If the operation succeeded then send back an HTTP positive response and the connection is consider established. After that, the proxy does not care what data is transferred between client requesting the connection and the destination. It just forwards data in both ways acting as a tunnel. <br><br>About the protocol<br>We are interested in CONNECT method from the HTTP protocol. After the applications opens a connection with the proxy server it must send the connect request in the form of an HTTP request: <br><br>CONNECT &lt;destination_address&gt;:&lt;destination_port&gt; &lt;http_version&gt;&lt;CR&gt;&lt;LF&gt;&lt;header_line&gt;&lt;CR&gt;&lt;LF&gt;&lt;header_line&gt;&lt;CR&gt;&lt;LF&gt;...&lt;header_line&gt;&lt;CR&gt;&lt;LF&gt;&lt;CR&gt;&lt;LF&gt;The proxy server process the request and try to make a connection to &lt;destionation_address&gt;:&lt;destination_port&gt;. <br><br>The proxy server sends back an HTTP response in the form: <br><br>&lt;http_version&gt; &lt;code&gt; &lt;message&gt;&lt;CR&gt;&lt;LF&gt;&lt;header_line&gt;&lt;CR&gt;&lt;LF&gt;&lt;header_line&gt;&lt;CR&gt;&lt;LF&gt;...&lt;header_line&gt;&lt;CR&gt;&lt;LF&gt;&lt;CR&gt;&lt;LF&gt;If it is a positive response (code=200) then after the empty line the proxy begins to acts as a tunnel and forwards data. If it is a negative response (code!=200) then connection is closed after the empty line. <br><br>The HTTPTunneling application<br>The application act as specified in a configuration file. An entry in the configuration file locks like this: <br><br>&lt;Source port&gt; &lt;Destination address&gt; &lt;Destination port&gt; &lt;Proxy address&gt; &lt;Proxy port&gt;If the application is running and an entry in the configuration files changes, the application automatically updates itself. <br><br>For every entry in the configuration file the application creates a port listener. This is a thread that opens a socket on &lt;Source port&gt; and waits for connection. When a request arrives on that port it tries to open a tunnel to the &lt;Destination address&gt;:&lt; port&gt;. If the &lt;Proxy address&gt; and &lt;Proxy port&gt; are missing, a direct connection is made. If the field are present it opens a connection to the proxy and sends a CONNECT request using the method specified above. The tunnel construction is made in a separate thread to let the port listener to accept immediatelly new connections. After the connection is established a tunnel object is constructed based on the opened sockets, sockets are marked as non-blocking and the object is passed to manager object. The thread that has created the tunnel is destroyed. Data transfer is made on a single thread. When one of the ends closes the connection the tunnel closes the other and the tunnel is marked as inactive. The manager finds the tunnel inactive and removes it from the list of active tunnels. By default the application generates log information in HTTPTunneling.log file. This file can be consulted to find wrong application behaviour.<br><img src ="http://www.cppblog.com/niewenlong/aggbug/64564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-21 02:29 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64564#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: 代理服务器代码</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64563</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 20 Oct 2008 18:25:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64563</guid><description><![CDATA[通过Socket5代理服务器访问网络的问题<br>SOCKS5<br><br>Socks5版本的协议说明参考 RFC1928,RFC1929<br>下面简单地罗列程序实现，不涉及详细的协议规范。首先对于TCP连接，然后再讨论UDP传输。至于通过socks5的多播通讯，有兴趣可以参考D. Chouinard的文章。<br><br>1、TCP:<br><br>// 建立流套接字 <br>SOCKET m_socTCP=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);<br><br>// 连接到代理服务器<br>int nRet = connect(m_socTCP,(SOCKADDR*)&amp;m_saiProxy,sizeof(m_saiProxy));<br><br>// Step 1: 连接代理服务器成功后，马上开始和代理协商，协商报文如下,询问服务器，版本5，是需要验证(0x02)还是不需要验证(0x00)<br>　　+------+-------------------+------------+<br>　　|VER   | Number of METHODS | METHODS    |<br>　　+------+-------------------+------------+<br>　　| 0x05 | 0x02 (有两个方法)  | 0x00 | 0x02|<br>　　+------+-------------------+------------+<br>const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};<br>nRet = send(m_socTCP,reqNego,4,0);<br><br>// Setp 2: 代理服务器将返回两个字节的协商结果，接收协商结果<br>fd_set fdread;FD_ZERO(&amp;fdread);<br>FD_SET(m_socTCP,&amp;fdread);<br>// Last param set to NULL for blocking operation. (struct timeval*)<br>if((nRet=select(0,&amp;fdread,NULL,NULL,NULL))==SOCKET_ERROR){return NC_E_PROXY_SELECT_READ|WSAGetLastError();}<br>char resNego[2]={'\0'};<br>int nRcvd=0,nCount=0;<br>while(1)<br>{<br>if(FD_ISSET(m_socTCP,&amp;fdread))<br>{<br>//接收sock[0]发送来的数据<br>do{<br>nRet = recv(m_socTCP, (char*)resNego+nRcvd, 2-nRcvd,0);<br>if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>nRcvd += nRet;<br>}<br>while((nRcvd!=2)&amp;&amp;(++nCount&lt;1000));<br>if(nRcvd==2) break;<br>}<br>if(nCount++&gt;=2000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>}<br>if(resNego[0]!=0x05 || (resNego[1]!=0x00 &amp;&amp; resNego[1]!=0x02)){return NC_E_PROXY_PROTOCOL_VERSION|WSAGetLastError();};<br><br>// Step 3: 根据协商结果判断是否需要验证用户，如果是0x02，则需要提供验证，验证部分参考RFC1929<br>if(resNego[1]==0x02)<br>{<br>// 需要密码验证<br>char reqAuth[513]={'\0'};<br>BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);<br>BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);<br>reqAuth[0]=0x01;<br>reqAuth[1]=byLenUser;<br>sprintf(&amp;reqAuth[2],&quot;%s&quot;,m_szProxyUserName);<br>reqAuth[2+byLenUser]=byLenPswd;<br>sprintf(&amp;reqAuth[3+byLenUser],&quot;%s&quot;,m_szProxyPassword);<br>//Send authentication info<br>int len = (int)byLenUser + (int)byLenPswd + 3;<br>nRet=send(m_socTCP,(const char*)reqAuth,len,0);<br>if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}<br>//Now : Response to the auth request<br>char resAuth[2]={'\0'};<br>int nRcvd=0,nCount=0;<br>do{<br>nRet = recv(m_socTCP,resAuth+nRcvd,2-nRcvd,0);<br>if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>nRcvd += nRet;<br>}<br>while((nRcvd!=2)&amp;&amp;(++nCount&lt;1000));<br>if(nCount&gt;=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>if (resAuth[1]!=0) return NC_E_PROXY_AUTHORIZE;<br>// 密码验证通过了<br>}<br><br>// Step 4: 协商完成，开始发送连接远程服务器请求,请求报文格式如下：<br>　　+----+-----+-------+------+----------+----------+<br>　　|VER | CMD |　RSV　| ATYP | DST.ADDR | DST.PORT |<br>　　+----+-----+-------+------+----------+----------+<br>　　| 1　| 　1 | 0x00  | 　1　| Variable |　　 2　　 |<br>　　+----+-----+-------+------+----------+----------+<br>// CMD==0x01 表示连接, ATYP==0x01表示采用IPV4格式地址，DST.ADDR是远程服务器地址，DST.PORT是远程服务器端口<br>// 如果需要接受外来连接，则需要在连接完成之后，发送CMD==0x02绑定请求，代理将为此请求绑定一个套接字接受外部连接<br>char reqSubNego[10]={(char)0x05,(char)0x01,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};<br>*(unsigned long*)&amp;reqSubNego[4] =m_saiServerTCP.sin_addr.S_un.S_addr;<br>*(unsigned short*)&amp;reqSubNego[8]=m_saiServerTCP.sin_port;<br>nRet=send(m_socTCP,(const char*)reqSubNego,10,0);<br>if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}<br><br>// Step 5: 接收对请求的响应，响应包格式如下<br>　　+----+-----+-------+------+----------+----------+<br>　　|VER | REP |　RSV　| ATYP | BND.ADDR | BND.PORT |<br>　　+----+-----+-------+------+----------+----------+<br>　　| 1　|　1　| 0x00  |　1 　 | Variable | 　　2 　 |<br>　　+----+-----+-------+------+----------+----------+<br>// VER 必须是0x05, REP==0x00表示成功，ATYP==0x01表示地址是IPV4地址，BND.ADDR 是代理为连接远程服务器绑定的地址，BND.PORT是这个套接字的端口<br>char resSubNego1[5]={'\0'};<br>if(FD_ISSET(m_socTCP,&amp;fdread))<br>{<br>int nRcvd=0,nCount=0;<br>do{<br>nRet = recv(m_socTCP,resSubNego1+nRcvd,5-nRcvd,0);<br>if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>nRcvd += nRet;<br>}<br>while((nRcvd!=5)&amp;&amp;(++nCount&lt;1000));<br>if(nCount&gt;=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>if(resSubNego1[0]!=0x05||resSubNego1[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB|WSAGetLastError();};<br><br>switch(resSubNego1[3])<br>{<br>case 0x01:<br>{<br>// IP V4<br>char resSubNego2[6]={resSubNego1[4],0};<br>int nRet=-1;<br>if(FD_ISSET(m_socTCP,&amp;fdread))<br>{<br>int nRcvd=0,nCount=0;<br>do{<br>int nRet = recv(m_socTCP,&amp;resSubNego2[1]+nRcvd,5-nRcvd,0);<br>if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>nRcvd += nRet;<br>}<br>while((nRcvd!=5)&amp;&amp;(++nCount&lt;1000));<br>if(nCount&gt;=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>}<br>// 得到代理绑定地址<br>unsigned long  ulBINDAddr = *(unsigned long*)&amp;resSubNego2; // SOCKS BIND ADDR<br>unsigned short usBINDPort = *(unsigned short*)&amp;resSubNego2[4]; // SOCKS BIND PORT<br>m_saiProxyBindTCP.sin_addr.S_un.S_addr=ulBINDAddr;<br>m_saiProxyBindTCP.sin_port=usBINDPort;<br>// 得到本机绑定地址<br>int len = sizeof(m_saiHostTCP);<br>getsockname(m_socTCP,(SOCKADDR*)&amp;m_saiHostTCP,&amp;len);<br>}<br>break;<br>case 0x03:<br>{<br>// Domain name<br>int nLen = resSubNego1[4]+2;<br>char* presSubNego2 = new char[nLen];<br>if(FD_ISSET(m_socTCP,&amp;fdread))<br>{<br>int nRet=0,nRcvd=0,nCount=0;<br>do{<br>nRet = recv(m_socTCP,presSubNego2+nRcvd,nLen-nRcvd,0);<br>if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>nRcvd += nRet;<br>}<br>while((nRcvd!=nLen)&amp;&amp;(++nCount&lt;1000));<br>if(nCount&gt;=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>}<br>unsigned short usBINDPort = *(unsigned short*)(presSubNego2+nLen-2); // BIND PORT;<br>// 此时得到的是远程主机的Domain Name<br>delete[] presSubNego2; presSubNego2=NULL;<br>}<br>break;<br>case 0x04:<br>{<br>// IPV6<br>AfxMessageBox(&quot;该版本不支持IPV6&quot;;<br>}<br>break;<br>default:<br>break;<br>}<br><br>// 至此，连接已经建立。在此套接字上可进行数据的收发。<br>}<br><br>2、UDP<br><br>SOCKS V5提供了对UDP的支持，它通过在代理服务器和内网主机之间建立一个UDP中继的TCP连接，来辅助进行UDP数据包的收发。此连接有一个有效期，在此有效生命周期内，必须往代理发送UDP数据报确认连接有效，来维持此连接的有效性，否则，代理服务器超时，将会自动释放此连接的资源。<br>下面简单地罗列程序实现，不涉及详细的协议规范。<br><br>// 客户端为UDP中继建立一个相关的流套接字<br>SOCKET m_socClientTCP_UdpAssociate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);<br><br>// 连接代理服务器<br>int nRet=connect(m_socClientTCP_UdpAssociate,(SOCKADDR*)&amp;saiProxy,sizeof(saiProxy));<br><br>// 连接成功，开始和代理服务器协商，首先发送版本标志，方法选择报文<br>const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};<br>nRet = send(m_socClientTCP_UdpAssociate,reqNego,4,0);<br>if( nRet==SOCKET_ERROR <br>{<br>DWORD dwError = WSAGetLastError();<br>if (dwError!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;<br>}<br><br>// 接收协商的响应<br>fd_set fdread; FD_ZERO(&amp;fdread);<br>FD_SET(m_socClientTCP_UdpAssociate,&amp;fdread);<br>if((nRet=select(0,&amp;fdread,NULL,NULL,NULL))==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;<br>char resNego[2]={0};<br>int nRcvd=0,nCount=0;<br>if(FD_ISSET(m_socClientTCP_UdpAssociate,&amp;fdread))<br>{<br>nRcvd = recv(m_socClientTCP_UdpAssociate, (char*)resNego+nRcvd, 2,0);<br>if(nRcvd==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;<br>}<br>if(resNego[0]!=0x05 || (resNego[1]!=0x00 &amp;&amp; resNego[1]!=0x02)) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;<br><br>// 看是否需要密码验证<br>if(resNego[1]==0x02)<br>{<br>// 需要密码验证<br>char reqAuth[513]; memset(reqAuth,0,513);<br>BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);<br>BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);<br>reqAuth[0]=0x01;<br>reqAuth[1]=byLenUser;<br>sprintf(&amp;reqAuth[2],&quot;%s&quot;,m_szProxyUserName);<br>reqAuth[2+byLenUser]=byLenPswd;<br>sprintf(&amp;reqAuth[3+byLenUser],&quot;%s&quot;,m_szProxyPassword);<br>//Send authentication info<br>int len = (int)byLenUser + (int)byLenPswd + 3;<br>int ret=send(m_socClientTCP_UdpAssociate,(const char*)reqAuth,len,0);<br>if (ret==SOCKET_ERROR) if (GetLastError()!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;<br><br>//Now : Response to the auth request<br>char resAuth[2]={'\0'};<br>int nRcvd=0,nCount=0;<br>do{<br>ret = recv(m_socClientTCP_UdpAssociate,resAuth+nRcvd,2-nRcvd,0);<br>if(ret==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>nRcvd += nRet;<br>}<br>while((nRcvd!=2)&amp;&amp;(++nCount&lt;1000));<br>if(nCount&gt;=1000){return NC_E_PROXY_RECEIVE}<br>if (resAuth[1]!=0)     return NEM_E_WM_CREATE_PROXYAUTHFAILED;<br>// 密码验证通过了<br>}<br><br>// 开始发送向目标服务器的连接请求，其中DST.ADDR是目标服务器的地址，DST.PORT是目标服务器的UDP端口<br>char reqSubNego[10]={(char)0x05,(char)0x03,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};<br>*(unsigned long*)&amp;reqSubNego[4] =saiServerUDP.sin_addr.S_un.S_addr; // cmd: DEST.addr<br>*(unsigned short*)&amp;reqSubNego[8]=saiServerUDP.sin_port; // cmd: DEST.port in network octet order<br>nRet=send(m_socClientTCP_UdpAssociate,(const char*)reqSubNego,10,0);<br>if (nRet==SOCKET_ERROR) return NEM_E_WM_CREATE_PROXYREQFAILED;<br><br>// 接收响应信息<br>int nRecvCount = 0;<br>int nRecvBufferLen = 10;<br>char szRecvBuf[10];<br>nRet = 0;<br>if(FD_ISSET(m_socClientTCP_UdpAssociate,&amp;fdread))<br>{<br>int nRcvd=0,nCount=0;<br>do{<br>nRet = recv(m_socClientTCP_UdpAssociate,(char*)szRecvBuf+nRcvd,10-nRcvd,0);<br>if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}<br>nRcvd += nRet;<br>}<br>while((nRcvd!=10)&amp;&amp;(++nCount&lt;1000));<br>if(nCount&gt;=1000){return NC_E_PROXY_RECEIVE;}<br>if (szRecvBuf[0]!=0x05||szRecvBuf[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB;}<br>}<br>else<br>{<br>return NCM_E_WM_CREATE_PROXYREQUESTFAILED;<br>}<br><br>// 代理服务器绑定udp地址BND.ADR，一般代理服务器都是多宿主机器，因此这个绑定地址是局域网地址，代理服务器绑定udp端口BND.PORT<br>// m_ulProxyUDPAddr 代理绑定地址<br>// m_usUDPAssociatePort 代理绑定端口<br>memmove(&amp;m_ulProxyUDPAddr,&amp;szRecvBuf[4],4);<br>memmove(&amp;m_usUDPAssociatePort,&amp;szRecvBuf[8],2);<br><br>m_bUDPAssociated = TRUE;<br>// 至此，得到了代理绑定的地址和端口，客户端就可以通过它来收发UDP数据报了<br><br><br>// 客户端收发实例<br>// 首先创建数据报套接字，绑定套接字，得到本地数据报套接字地址，端口<br>SOCKET m_socClientUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);<br>SOCKADDR_IN saiLocal;<br>memset(&amp;saiLocal,0,sizeof(saiLocal));<br>saiLocal.sin_family = AF_INET;<br>saiLocal.sin_port = 0;<br>saiLocal.sin_addr.S_un.S_addr = INADDR_ANY;<br>// 绑定本地udp套接字地址，地址+端口由系统决定<br>if (bind(m_socClientUDP, (SOCKADDR *)&amp;saiLocal, sizeof(saiLocal)  == SOCKET_ERROR)<br>getsockname(m_socClientUDP, (sockaddr*)&amp;saiLocal, &amp;len);<br>// m_ulHostAddr 本机绑定地址<br>// m_usHostPortUdp 本机绑定端口<br>m_ulHostAddr = saiLocal.sin_addr.S_un.S_addr;<br>m_usHostPortUdp = saiLocal.sin_port;<br><br>// 按照格式，发送数据<br>SOCKADDR_IN saiProxy;<br>memset(&amp;saiProxy,0,sizeof(saiProxy));<br>saiProxy.sin_family = AF_INET;<br>saiProxy.sin_addr.S_un.S_addr = m_ulProxyUDPAddr; // 代理绑定的udp地址<br>saiProxy.sin_port = m_usUDPAssociatePort; // 代理绑定的udp端口<br><br>// 每个UDP包必须携带如下所述的头：<br>      +----+------+------+----------+----------+----------+<br>      |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |<br>      +----+------+------+----------+----------+----------+<br>      | 2  |  1   |  1   | Variable |    2     | Variable |<br>      +----+------+------+----------+----------+----------+<br>// 其中 ATYP==0x01 表示采用 IPV4 地址，那么头长度就是10，DST.ADDR并不是服务器地址，而是本机绑定地址，DST.PORT是本机绑定端口<br>char buf[10+2]={'0x00','0x00','0x00','0x01','0xff'};<br>memmove(&amp;buf[4],&amp;m_ulHostAddr,4);<br>*(unsigned short*)&amp;buf[8]=m_usHostPortUDP;<br>int nRet = sendto(m_socClientUDP,buf,12,0,(SOCKADDR*)&amp;saiProxy,sizeof(saiProxy));<br><br>// 接收数据<br>int nLen = sizeof(saiProxy);<br>char buf=new char[MAX_UDPLEN];<br>nRet = recvfrom(m_socClientUDP,buf,MAX_UDPLEN,0,(SOCKADDR *)&amp;saiProxy,&amp;nLen);<br>if(nRet==SOCKET_ERROR) return SOCKET_ERROR;<br>BYTE flag=0xff;<br>if(memcmp(&amp;buf[0],&amp;flag,1)==0) return SOCKET_ERROR;<br>BYTE byProxyHead[20];<br>byProxyHead[0]=byProxyHead[1]=byProxyHead[2]=0;<br>byProxyHead[3]=1;<br>*(unsigned long*)&amp;byProxyHead[4] = saiServerUDP.sin_addr.S_un.S_addr;<br>*(unsigned short*)&amp;byProxyHead[8] = saiServerUDP.sin_port;<br>byProxyHead[10]=byProxyHead[11]=byProxyHead[12]=0;<br>byProxyHead[13]=1;<br>*(unsigned long*)&amp;byProxyHead[14] = m_ulHostAddr;<br>*(unsigned short*)&amp;byProxyHead[18] = m_usHostPortUdp;<br><br>int i=0;<br>BOOL bIsForMe=FALSE;<br>if(memcmp(&amp;byProxyHead[0],&amp;buf[i],4)==0)<br>{<br>unsigned long ulRetAddr = *(unsigned long*)&amp;buf[i+4];<br>if(ulRetAddr==m_ulHostAddr)<br>{<br>unsigned short usRetPort = ntohs((unsigned short)(*(unsigned short*)&amp;buf[i+8]));<br>if(usRetPort==m_usHostPortUdp)<br>{<br>bIsForMe=TRUE;<br>}<br>}<br>i+=10;<br>}<br>// 客户端收发结束<br><br><br>// 服务器端发送实例<br>// m_ulProxyUDPAddr 代理绑定地址<br>// m_usUDPAssociatePort 代理绑定端口<br>// m_ulHostAddr 本机绑定地址<br>// m_usHostPortUdp 本机绑定端口<br>// 客户端必须把上面的m_ulProxyUDPAddr,m_usUDPAssociatePort,m_ulHostAddr,m_usHostPortUdp告知服务器，服务器通过这两个套接字进行数据的收发<br><br>// 服务器创建数据报套接字<br>SOCKET m_socUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);<br><br>// 代理的udp中继地址<br>SOCKADDR_IN saiClient;<br>saiClient.sin_family = AF_INET;<br>saiClient.sin_addr.S_un.S_addr = m_ulProxyUDPAddr;<br>saiClient.sin_port = m_usUDPAssociatePort;<br>// 如果远程目标在代理服务器后面，透过代理，指定远程目标的socks信息，参照RFC1928<br>char buffer[10]={'\0'};<br>buffer[0]=buffer[1]=buffer[2]=0;<br>buffer[3]=1; // No Fragment, It's a dependent udp, no need for socks server to arrange udp fragments<br><br>// 目标机器的地址端口，透过代理后发向这里<br>*(int*)&amp;buffer[4]=m_ulHostAddr;<br>*(unsigned short*)&amp;buffer[8]=m_usHostPortUdp;<br>BYTE buf[DATA_BUFSIZE]={'\0'};<br>memmove(&amp;buf[10],&amp;szSendbuf[0],dwLength);<br>memmove(&amp;buf[0],&amp;buffer[0],10);<br>int nSent = sendto(m_socUDP, (const char*)&amp;buf[0], dwLength+10, 0, (SOCKADDR*)&amp;saiClient,sizeof(saiClient));<br>// 服务器端发送结束<img src ="http://www.cppblog.com/niewenlong/aggbug/64563.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-21 02:25 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64563#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: 代理服务器代码</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64562</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 20 Oct 2008 18:23:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64562</guid><description><![CDATA[VC++6实现简单的代理服务器 <br><br>本文转自CSDN的blog：<a target="_new" href="http://blog.csdn.net/snaill/archive/2006/03/14/624437.aspx">http://blog.csdn.net/snaill/archive/2006/03/14/624437.aspx</a> <br><br>#include &quot;stdafx.h&quot; <br>#include &quot;Proxy.h&quot; <br>#include &lt; winsock2.h &gt; //WINSOCKET API 2。0 <br>#include &lt; stdlib.h &gt; <br>#include &lt; stdio.h &gt; <br>#include &lt; string.h &gt; <br><br>#ifdef _DEBUG <br>#define new DEBUG_NEW <br>#undef THIS_FILE <br>static char THIS_FILE[] = __FILE__; <br>#endif <br><br>///////////////////////////////////////////////////////////////////////////// <br><br><br>#define HTTP &quot;http://&quot; <br>#define FTP &quot;ftp://&quot; <br>#define PROXYPORT 5001 //Proxy 端口 <br>#define BUFSIZE 10240 //缓冲区大小 <br><br><br>CWinApp theApp; <br><br>using namespace std; <br><br>UINT ProxyToServer(LPVOID pParam); <br>UINT UserToProxyThread(void *pParam); <br><br>struct SocketPair{ <br>SOCKET user_proxy; //socket : 本地机器到PROXY 服务机 <br>SOCKET proxy_server; //socket : PROXY 服务机到远程主机 <br>BOOL IsUser_ProxyClosed; // 本地机器到PROXY 服务机状态 <br>BOOL IsProxy_ServerClosed; // PROXY 服务机到远程主机状态 <br>}; <br><br><br>struct ProxyParam{ <br>char Address[256]; // 远程主机地址 <br>HANDLE User_SvrOK; // PROXY 服务机到远程主机的联结状态 <br>SocketPair *pPair; // 维护一组SOCKET的指针 <br>int Port; // 用来联结远程主机的端口 <br>}; //这个结构用来PROXY SERVER与远程主机的信息交换. <br><br>SOCKET gListen_Socket; //用来侦听的SOCKET。 <br><br>int StartServer() //启动服务 <br>{ <br>WSADATA wsaData; <br>sockaddr_in local; <br>SOCKET listen_socket; <br><br>if(::WSAStartup(0x202,&amp;wsaData)!=0) <br>{printf(&quot;\nError in Startup session.\n&quot;);WSACleanup();return -1;}; <br><br>local.sin_family=AF_INET; <br>local.sin_addr.s_addr=INADDR_ANY; <br>local.sin_port=htons(PROXYPORT); <br><br>listen_socket=socket(AF_INET,SOCK_STREAM,0); <br>if(listen_socket==INVALID_SOCKET) <br>{printf(&quot;\nError in New a Socket.&quot;);WSACleanup();return -2;} <br><br>if(::bind(listen_socket,(sockaddr *)&amp;local,sizeof(local))!=0) <br>{printf(&quot;\n Error in Binding socket.&quot;); WSACleanup();return -3; }; <br><br>if(::listen(listen_socket,5)!=0) <br>{printf(&quot;\n Error in Listen.&quot;); WSACleanup(); return -4;} <br>gListen_Socket=listen_socket; <br>AfxBeginThread(UserToProxyThread,NULL); //启动侦听 <br>return 1; <br>} <br><br>int CloseServer() //关闭服务 <br>{ <br>closesocket(gListen_Socket); <br>WSACleanup(); <br>return 1; <br>} <br>//分析接收到的字符，得到远程主机地址 <br><br>int GetAddressAndPort( char * str, char *address, int * port) <br>{ <br>char buf[BUFSIZE], command[512], proto[128], *p; <br>int j; <br>sscanf(str,&quot;%s%s%s&quot;,command,buf,proto); <br>p=strstr(buf,HTTP); <br>//HTTP <br>if(p) <br>{ <br>p+=strlen(HTTP); <br>for(int i=0;i&lt; strlen(p);i++) <br>if( *(p+i)=='/') break; <br>*(p+i)=0; <br>strcpy(address,p); <br>p=strstr(str,HTTP); <br>for(int j=0;j&lt; i+strlen(HTTP);j++) <br>*(p+j)=' '; //去掉远程主机名: GET http:/www.csdn.net/ HTTP1.1 == &gt; GET / HTTP1.1 <br>*port=80; //缺省的 http 端口 <br>} <br>else <br>{//FTP, 不支持, 下面的代码可以省略. <br>p=strstr(buf,FTP); <br>if(!p) return 0; <br>p+=strlen(FTP); <br>for(int i=0;i&lt; strlen(p);i++) <br>if( *(p+i)=='/') break; //Get The Remote Host <br>*(p+i)=0; <br>for(j=0;j&lt; strlen(p);j++) <br>if(*(p+j)==':') <br>{*port=atoi(p+j+1); //Get The Port <br>*(p+j)=0; <br>} <br>else *port=21; <br><br>strcpy(address,p); <br>p=strstr(str,FTP); <br>for(j=0;j&lt; i+strlen(FTP);j++) <br>*(p+j)=' '; <br>} <br>return 1; <br>} <br><br>// 取到本地的数据，发往远程主机 <br>UINT UserToProxyThread(void *pParam) <br>{ <br>char Buffer[BUFSIZE]; <br>int Len; <br>sockaddr_in from; <br>SOCKET msg_socket; <br>int fromlen,retval; <br>SocketPair SPair; <br>ProxyParam ProxyP; <br>CWinThread *pChildThread; <br>fromlen=sizeof(from); <br>msg_socket=accept(gListen_Socket,(struct sockaddr*)&amp;from,&amp;fromlen); <br>AfxBeginThread(UserToProxyThread,pParam); //启动另一侦听. <br>if( msg_socket==INVALID_SOCKET) <br>{ printf( &quot;\nError in accept &quot;); return -5;} <br>//读客户的第一行数据 <br><br>SPair.IsUser_ProxyClosed=FALSE; <br>SPair.IsProxy_ServerClosed=TRUE; <br>SPair.user_proxy=msg_socket; <br><br>retval=recv(SPair.user_proxy,Buffer,sizeof(Buffer),0); <br><br>if(retval==SOCKET_ERROR) <br>{ printf(&quot;\nError Recv&quot;); <br>if(SPair.IsUser_ProxyClosed==FALSE) <br>{closesocket(SPair.user_proxy); <br>SPair.IsUser_ProxyClosed=TRUE; <br>} <br>} <br>if(retval==0) <br>{printf(&quot;Client Close connection\n&quot;); <br>if(SPair.IsUser_ProxyClosed==FALSE) <br>{closesocket(SPair.user_proxy); <br>SPair.IsUser_ProxyClosed=TRUE; <br>} <br>} <br>Len=retval; <br>#ifdef _DEBUG <br><br>Buffer[Len]=0; <br>printf(&quot;\n Received %d bytes,data[%s]from client\n&quot;,retval,Buffer); <br>#endif <br>// <br>SPair.IsUser_ProxyClosed=FALSE; <br>SPair.IsProxy_ServerClosed=TRUE; <br>SPair.user_proxy=msg_socket; <br><br>ProxyP.pPair=&amp;SPair; <br>ProxyP.User_SvrOK=CreateEvent(NULL,TRUE,FALSE,NULL); <br><br>GetAddressAndPort( Buffer,ProxyP.Address,&amp;ProxyP.Port); <br><br>pChildThread=AfxBeginThread(ProxyToServer,(LPVOID)&amp;ProxyP); <br>::WaitForSingleObject(ProxyP.User_SvrOK,60000); //等待联结 <br>::CloseHandle(ProxyP.User_SvrOK); <br><br>while(SPair.IsProxy_ServerClosed ==FALSE &amp;&amp; SPair.IsUser_ProxyClosed==FALSE) <br>{ <br>retval=send(SPair.proxy_server,Buffer,Len,0); <br>if(retval==SOCKET_ERROR) <br>{ printf(&quot;\n send() failed:error%d\n&quot;,WSAGetLastError()); <br>if(SPair.IsProxy_ServerClosed==FALSE) <br>{ <br>closesocket(SPair.proxy_server); <br>SPair.IsProxy_ServerClosed=TRUE; <br>} <br>continue; <br>} <br>retval=recv(SPair.user_proxy,Buffer,sizeof(Buffer),0); <br><br>if(retval==SOCKET_ERROR) <br>{ printf(&quot;\nError Recv&quot;); <br>if(SPair.IsUser_ProxyClosed==FALSE) <br>{closesocket(SPair.user_proxy); <br>SPair.IsUser_ProxyClosed=TRUE; <br>} <br>continue; <br>} <br>if(retval==0) <br>{printf(&quot;Client Close connection\n&quot;); <br>if(SPair.IsUser_ProxyClosed==FALSE) <br>{closesocket(SPair.user_proxy); <br>SPair.IsUser_ProxyClosed=TRUE; <br>} <br>break; <br>} <br>Len=retval; <br>#ifdef _DEBUG <br>Buffer[Len]=0; <br>printf(&quot;\n Received %d bytes,data[%s]from client\n&quot;,retval,Buffer); <br>#endif <br><br>} //End While <br><br>if(SPair.IsProxy_ServerClosed==FALSE) <br>{ <br>closesocket(SPair.proxy_server); <br>SPair.IsProxy_ServerClosed=TRUE; <br>} <br>if(SPair.IsUser_ProxyClosed==FALSE) <br>{closesocket(SPair.user_proxy); <br>SPair.IsUser_ProxyClosed=TRUE; <br>} <br>::WaitForSingleObject(pChildThread- &gt;m_hThread,20000); //Should check the return value <br>return 0; <br>} <br>// 读取远程主机数据，并发往本地客户机 <br>UINT ProxyToServer(LPVOID pParam){ <br>ProxyParam * pPar=(ProxyParam*)pParam; <br>char Buffer[BUFSIZE]; <br>char *server_name= &quot;localhost&quot;; <br>unsigned short port ; <br>int retval,Len; <br>unsigned int addr; <br>int socket_type ; <br>struct sockaddr_in server; <br>struct hostent *hp; <br>SOCKET conn_socket; <br><br>socket_type = SOCK_STREAM; <br>server_name = pPar- &gt;Address; <br>port = pPar- &gt;Port; <br><br>if (isalpha(server_name[0])) { /* server address is a name */ <br>hp = gethostbyname(server_name); <br>} <br>else { /* Convert nnn.nnn address to a usable one */ <br>addr = inet_addr(server_name); <br>hp = gethostbyaddr((char *)&amp;addr,4,AF_INET); <br>} <br>if (hp == NULL ) { <br>fprintf(stderr,&quot;Client: Cannot resolve address [%s]: Error %d\n&quot;, <br>server_name,WSAGetLastError()); <br>::SetEvent(pPar- &gt;User_SvrOK); <br>return 0; <br>} <br><br>// <br>// Copy the resolved information into the sockaddr_in structure <br>// <br>memset(server,0,sizeof(server)); <br>memcpy(&amp;(server.sin_addr),hp- &gt;h_addr,hp- &gt;h_length); <br>server.sin_family = hp- &gt;h_addrtype; <br>server.sin_port = htons(port); <br><br>conn_socket = socket(AF_INET,socket_type,0); /* 打开一个 socket */ <br>if (conn_socket &lt; 0 ) { <br>fprintf(stderr,&quot;Client: Error Opening socket: Error %d\n&quot;, <br>WSAGetLastError()); <br>pPar- &gt;pPair- &gt;IsProxy_ServerClosed=TRUE; <br>::SetEvent(pPar- &gt;User_SvrOK); <br>return -1; <br>} <br>#ifdef _DEBUG <br>printf(&quot;Client connecting to: %s\n&quot;,hp- &gt;h_name); <br>#endif <br>if (connect(conn_socket,(struct sockaddr*)server,sizeof(server)) <br>== SOCKET_ERROR) { <br>fprintf(stderr,&quot;connect() failed: %d\n&quot;,WSAGetLastError()); <br>pPar- &gt;pPair- &gt;IsProxy_ServerClosed=TRUE; <br>::SetEvent(pPar- &gt;User_SvrOK); <br>return -1; <br>} <br>pPar- &gt;pPair- &gt;proxy_server=conn_socket; <br>pPar- &gt;pPair- &gt;IsProxy_ServerClosed=FALSE; <br>::SetEvent(pPar- &gt;User_SvrOK); <br>// cook up a string to send <br>while(!pPar- &gt;pPair- &gt;IsProxy_ServerClosed &amp;&amp;!pPar- &gt;pPair- &gt;IsUser_ProxyClosed) <br>{ <br>retval = recv(conn_socket,Buffer,sizeof (Buffer),0 ); <br>if (retval == SOCKET_ERROR ) { <br>fprintf(stderr,&quot;recv() failed: error %d\n&quot;,WSAGetLastError()); <br>closesocket(conn_socket); <br>pPar- &gt;pPair- &gt;IsProxy_ServerClosed=TRUE; <br>break; <br>} <br>Len=retval; <br>if (retval == 0) { <br>printf(&quot;Server closed connection\n&quot;); <br>closesocket(conn_socket); <br>pPar- &gt;pPair- &gt;IsProxy_ServerClosed=TRUE; <br>break; <br>} <br><br>retval = send(pPar- &gt;pPair- &gt;user_proxy,Buffer,Len,0); <br>if (retval == SOCKET_ERROR) { <br>fprintf(stderr,&quot;send() failed: error %d\n&quot;,WSAGetLastError()); <br>closesocket(pPar- &gt;pPair- &gt;user_proxy); <br>pPar- &gt;pPair- &gt;IsUser_ProxyClosed=TRUE; <br>break; <br>} <br>#ifdef _DEBUG <br>Buffer[Len]=0; <br>printf(&quot;Received %d bytes, data [%s] from server\n&quot;,retval,Buffer); <br>#endif <br>} <br>if(pPar- &gt;pPair- &gt;IsProxy_ServerClosed==FALSE) <br>{ <br>closesocket(pPar- &gt;pPair- &gt;proxy_server); <br>pPar- &gt;pPair- &gt;IsProxy_ServerClosed=TRUE; <br>} <br>if(pPar- &gt;pPair- &gt;IsUser_ProxyClosed==FALSE) <br>{closesocket(pPar- &gt;pPair- &gt;user_proxy); <br>pPar- &gt;pPair- &gt;IsUser_ProxyClosed=TRUE; <br>} <br>return 1; <br>} <br><br><br><br>int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) <br>{ <br>int nRetCode = 0; <br><br>// 初始化SOCKET <br>if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) <br>{ <br>// 错误处理 <br>cerr &lt; &lt; _T(&quot;Fatal Error: MFC initialization failed&quot;) &lt; &lt; endl; <br>nRetCode = 1; <br>} <br>else <br>{ <br>// 主程序开始. <br>StartServer(); <br>while(1) <br>if(getchar()=='q') break; <br>CloseServer(); <br>} <br><br>return nRetCode; <br>} <img src ="http://www.cppblog.com/niewenlong/aggbug/64562.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-21 02:23 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64562#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>re: 代理服务器代码</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64561</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 20 Oct 2008 18:22:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64561</guid><description><![CDATA[打造自己的HTTP代理服务器<br>#include &quot;stdafx.h&quot;<br>#include &quot;HTTPPROXY.h&quot;<br>#define FD_NOEVENT 0<br>//<br>#define BACKUP 100<br>#define MAXDATALEN 65535<br>int HttpListenPort;<br>SOCKET HttpListenSock;<br>//<br>typedef struct _CLIENTINFO{<br>SOCKET clientsock;<br>SOCKET udpsock;<br>sockaddr_in clientsock_addr;<br>}CLIENTINFO,*LPCLIENTINFO;<br>CLIENTINFO HttpClientInfo;<br>//<br>typedef struct _SOCKINFO{<br>SOCKET sourcesock;<br>SOCKET destsock;<br>}SOCKINFO,*LPSOCKINFO;<br>SOCKINFO httpsockinfo;<br>//<br>extern long GetSocketEventId(SOCKET remotesock);<br>extern unsigned long GetLocalIp();<br>extern unsigned long GetDomainIp(char domainname[250]);<br>/*<br>long GetSocketEventId(SOCKET remotesock){<br>long EventId;<br>HANDLE hevent;<br>hevent=CreateEvent(NULL,0,0,0);<br>WSANETWORKEVENTS socket_events;<br>EventId=FD_NOEVENT;<br>if(WSAEventSelect(remotesock,hevent,FD_ACCEPT|FD_CONNECT|FD_<br>READ|FD_WRITE|FD_CLOSE)==SOCKET_ERROR) return EventId;<br>WSAEnumNetworkEvents(remotesock,hevent,&amp;socket_events);<br>if(socket_events.lNetworkEvents!=0){<br>switch(socket_events.lNetworkEvents){<br>case FD_ACCEPT:EventId=FD_ACCEPT;break;<br>case FD_CONNECT:EventId=FD_CONNECT;break;<br>case FD_READ:EventId=FD_READ;break;<br>case FD_WRITE:EventId=FD_WRITE;break;<br>case FD_CLOSE:EventId=FD_CLOSE;break;<br>case FD_OOB:EventId=FD_OOB;break;<br>default:EventId=FD_NOEVENT;break;<br>}<br>}<br>else EventId=FD_NOEVENT;<br>return EventId;<br>}<br>//<br>unsigned long GetLocalIp()<br>{<br>char IP[MAX_PATH],*ip;<br>char pc_name[80];<br>struct in_addr in;<br>struct hostent *host;<br>WORD wVersionRequested;<br>WSADATA wsaData;<br>wVersionRequested=MAKEWORD(2,0);<br>ip=IP;<br>strcpy(ip,&quot;Ip not get!&quot;);<br>if(WSAStartup(wVersionRequested,&amp;wsaData)) return 0;<br>if(gethostname(pc_name,80)==SOCKET_ERROR){<br>WSACleanup();<br>return 0;<br>}<br>if(!(host=gethostbyname(pc_name))){<br>WSACleanup();<br>return 0;<br>}<br>in.s_addr=*((unsigned long *)host-&gt;h_addr_list[0]);<br>strcpy(ip,inet_ntoa(in));<br>WSACleanup();<br>return in.s_addr;<br>}<br>//<br>unsigned long GetDomainIp(char domainname[250])<br>{<br>char IP[MAX_PATH],*ip;<br>struct in_addr in;<br>struct hostent *host;<br>WORD wVersionRequested;<br>WSADATA wsaData;<br>wVersionRequested=MAKEWORD(2,0);<br>ip=IP;<br>strcpy(ip,&quot;Ip not get!&quot;);<br>if(WSAStartup(wVersionRequested,&amp;wsaData)) return 0;<br>if(!(host=gethostbyname(domainname))){<br>WSACleanup();<br>return 0;<br>}<br>in.s_addr=*((unsigned long *)host-&gt;h_addr_list[0]);<br>strcpy(ip,inet_ntoa(in));<br>WSACleanup();<br>return in.s_addr;<br>}<br>*/<br>//<br>//<br>UINT HttpReciveThread(LPVOID info){ //针对客户端的接收处理线程<br>LPSOCKINFO psockinfo; <br>SOCKET sourcesock,destsock;<br>char data[MAXDATALEN];<br>long eventid;<br>int datalen;<br>psockinfo=(LPSOCKINFO)info;<br>sourcesock=psockinfo-&gt;sourcesock;<br>destsock=psockinfo-&gt;destsock;<br>TRACE(&quot;deail recive thread ok!\r\n&quot;);<br>while(true){<br>eventid=GetSocketEventId(sourcesock);<br>switch(eventid){<br>case FD_CLOSE:<br>TRACE(&quot;s fdclosed\r\n&quot;);<br>closesocket(destsock);<br>return 1;<br>break;<br>default:break;<br>}<br>eventid=GetSocketEventId(destsock);<br>switch(eventid){<br>case FD_CLOSE:<br>closesocket(sourcesock);<br>TRACE(&quot;d fdclosed\r\n&quot;);<br>return 1;<br>break;<br>default:break;<br>}<br>datalen=recv(sourcesock,data,sizeof(data),0);<br>if(datalen==0){<br>closesocket(sourcesock);<br>closesocket(destsock);<br>TRACE(&quot;s fdclosed\r\n&quot;);<br>break;<br>}<br>if(datalen&gt;0){<br>while(!send(destsock,data,datalen,0));<br>}<br>Sleep(1);<br>}<br>return 1;<br>}<br>//<br>UINT HttpSendThread(LPVOID info){ //针对远程端的接收处理线程<br>LPSOCKINFO psockinfo;<br>SOCKET sourcesock,destsock;<br>char data[MAXDATALEN];<br>long eventid;<br>int datalen;<br>psockinfo=(LPSOCKINFO)info;<br>sourcesock=psockinfo-&gt;sourcesock;<br>destsock=psockinfo-&gt;destsock;<br>TRACE(&quot;deail send thread ok!\r\n&quot;);<br>while(true){<br>eventid=GetSocketEventId(sourcesock);<br>switch(eventid){<br>case FD_CLOSE:<br>TRACE(&quot;s fdclosed\r\n&quot;);<br>closesocket(destsock);<br>return 1;<br>break;<br>default:break;<br>}<br>eventid=GetSocketEventId(destsock);<br>switch(eventid){<br>case FD_CLOSE:<br>closesocket(sourcesock);<br>TRACE(&quot;d fdclosed\r\n&quot;);<br>return 1;<br>break;<br>default:break;<br>}<br>datalen=recv(destsock,data,sizeof(data),0);<br>if(datalen==0){<br>closesocket(sourcesock);<br>closesocket(destsock);<br>TRACE(&quot;d fdclosed\r\n&quot;);<br>break;<br>}<br>if(datalen&gt;0){<br>while(!send(sourcesock,data,datalen,0));<br>}<br>Sleep(1);<br>}<br>return 1;<br>}<br>//<br>//<br>UINT HttpProxyServerThread(LPVOID info){ //针对一次服务的线程<br>LPCLIENTINFO pclientinfo;<br>SOCKET connectsock,clientsock;<br>sockaddr_in remotesock_addr;<br>char data[MAXDATALEN],url[250],temp[250],httpurl[250],portnum[10];<br>int datalen,i,index_start,index_end,port;<br>CString HttpString,UrlString,PortString;<br>pclientinfo=(LPCLIENTINFO)info;<br>clientsock=pclientinfo-&gt;clientsock;<br>ZeroMemory((void *)data,sizeof(data));<br>datalen=recv(clientsock,data,sizeof(data),0);<br>if(datalen&lt;=0){<br>closesocket(clientsock);<br>return 0;<br>}<br>HttpString.Format(&quot;%s&quot;,data);<br>UrlString=HttpString;<br>TRACE(&quot;get http string:\r\n&quot;);<br>TRACE(HttpString);<br>index_start=HttpString.Find(&quot;Host: &quot;,0); //寻找url标记<br>if(index_start&lt;=0){<br>closesocket(clientsock);<br>return 0;<br>}<br>index_end=HttpString.Find(&quot;\r\n&quot;,index_start);<br>if(index_end&lt;=0){<br>closesocket(clientsock);<br>return 0;<br>}<br>UrlString=HttpString.Mid(index_start+6,index_end-index_start-6); //读取 url字符串<br>TRACE(&quot;\r\n get url:&quot;);<br>TRACE(UrlString);<br>wsprintf(url,&quot;%s&quot;,UrlString);<br>strcpy(temp,url);<br>strcat(temp,&quot;:&quot;);<br>datalen=strlen(temp);<br>if(HttpString.Find(&quot;GET&quot;,0)==0){ //判断get命令，并处理<br>index_start=HttpString.Find(temp,0);<br>strcpy(httpurl,&quot;http://&quot;);<br>if(index_start&gt;0){<br>index_end=HttpString.Find(&quot;/&quot;,index_start);<br>if(index_end&lt;=0){<br>closesocket(clientsock);<br>return 0;<br>}<br>PortString=HttpString.Mid(index_start+datalen,index_end-index_start-datalen);<br>port=atoi(PortString);<br>strcat(httpurl,temp);<br>itoa(port,portnum,sizeof(portnum));<br>strcat(httpurl,portnum);<br>strcat(httpurl,&quot;/&quot;);<br>}<br>else{<br>port=80;<br>strcat(httpurl,url);<br>strcat(httpurl,&quot;/&quot;);<br>}<br>TRACE(&quot;get http url:%s\r\n&quot;,httpurl);<br>HttpString.Replace(httpurl,&quot;/&quot;);<br>HttpString.Replace(&quot;Proxy-&quot;,&quot;&quot;);<br>HttpString.Replace(&quot;HTTP/1.0&quot;,&quot;HTTP/1.1&quot;);<br>}<br>else if(HttpString.Find(&quot;CONNECT&quot;,0)==0){ //判断connect命令并处理<br>index_start=HttpString.Find(temp,0);<br>if(index_start&gt;0){<br>index_end=HttpString.Find(&quot; &quot;,index_start);<br>if(index_end&lt;=0){<br>closesocket(clientsock);<br>return 0;<br>}<br>PortString=HttpString.Mid(index_start+datalen,index_end-index_start-datalen);<br>port=atoi(PortString);<br>}<br>else{<br>closesocket(clientsock);<br>return 0;<br>}<br>}<br>TRACE(&quot;get new http string:\r\n&quot;);<br>TRACE(HttpString);<br>remotesock_addr.sin_family=AF_INET;<br>remotesock_addr.sin_port=htons(port);<br>remotesock_addr.sin_addr.S_un.S_addr=GetDomainIp(url);<br>connectsock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);<br>if(connect(connectsock,(const sockaddr *)&amp;remotesock_addr,sizeof(remotesock_addr))==INVALID_SOCKET){ //连接远程主机<br>closesocket(clientsock);<br>return 0;<br>}<br>TRACE(&quot;\r\nconnect to remote ip ok\r\n&quot;); <br>ZeroMemory((void *)data,sizeof(data));<br>wsprintf(data,&quot;%s&quot;,HttpString);<br>datalen=strlen(data);<br>if(HttpString.Find(&quot;CONNECT&quot;,0)&lt;0) while(!send(connectsock,data,datalen,0));<br>else{<br>strcpy(data,&quot;HTTP/1.0 200 Connection established\r\nProxy-agent: CHTTPPROXY V1.0 powered by shadow\r\n\r\n&quot;);<br>datalen=strlen(data);<br>while(!send(clientsock,data,datalen,0));<br>}<br>httpsockinfo.sourcesock=clientsock;<br>httpsockinfo.destsock=connectsock;<br>AfxBeginThread(HttpReciveThread,(LPVOID)&amp;httpsockinfo); //抛出处理线程 <br>AfxBeginThread(HttpSendThread,(LPVOID)&amp;httpsockinfo); //<br>Sleep(100);<br>return 1;<br>}<br>//<br>UINT StartHttpProxy(LPVOID info){ //端口监听线程<br>SOCKET NewSock;<br>int socklen;<br>sockaddr_in serversock,remotesock_addr;<br>serversock.sin_family=AF_INET;<br>serversock.sin_addr.S_un.S_addr=INADDR_ANY;<br>serversock.sin_port=htons(HttpListenPort);<br>HttpListenSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);<br>if(HttpListenSock==INVALID_SOCKET) return 0;<br>if(bind(HttpListenSock,(const sockaddr *)&amp;serversock,<br>sizeof(serversock))==SOCKET_ERROR) return 0;<br>listen(HttpListenSock,BACKUP);<br>socklen=sizeof(remotesock_addr);<br>TRACE(&quot;start http proxy thread while\r\n&quot;);<br>while(true){<br>NewSock=accept(HttpListenSock,(sockaddr *)&amp;remotesock_addr,&amp;socklen);<br>TRACE(&quot;waitting ok...\r\n&quot;);<br>if(NewSock==INVALID_SOCKET){<br>Sleep(1);<br>continue;<br>}<br>ZeroMemory((void *)&amp;HttpClientInfo,sizeof(CLIENTINFO));<br>HttpClientInfo.clientsock=NewSock;<br>HttpClientInfo.clientsock_addr=remotesock_addr;<br>TRACE(&quot;start proxy thread\r\n&quot;);<br>AfxBeginThread(HttpProxyServerThread,(LPVOID)&amp;HttpClientInfo);<br>Sleep(100);<br>}<br>return 1;<br>}<br>//<br>CHTTPPROXY::CHTTPPROXY()<br>{<br>WSADATA WsaData;<br>WORD wsaVer;<br>wsaVer=MAKEWORD(2,0);<br>WsaStartupOk=false;<br>if(WSAStartup(wsaVer,&amp;WsaData)!=SOCKET_ERROR) WsaStartupOk=true;<br>}<br><br>CHTTPPROXY::~CHTTPPROXY()<br>{<br>if(WsaStartupOk){<br>WSACleanup();<br>}<br>}<br><br>int CHTTPPROXY::StartProxy(int listenport)<br>{<br>HttpListenPort=listenport;<br>AfxBeginThread(StartHttpProxy,(LPVOID)NULL);<br>return 1;<br>}<br><br><br>/*=========================================================<br>FILE:HTTPPROXY.h<br>==========================================================*/<br>class CHTTPPROXY <br>{<br>public:<br>int StartProxy(int listenport);<br>bool WsaStartupOk;<br>CHTTPPROXY();<br>virtual ~CHTTPPROXY();<br><br>};<br><br>/*==================================================<br>FILE:stdafx.h<br>===================================================*/<br>#include <br>#include <br>#include <br>#include<br><br><br>注:不要忘了在link选项中添加wsock32.lib和ws2_32.lib，或在文件前部加上如下语句：<br>#paragma comment(lib,&quot;wsock32.lib&quot;)<br>#paragma comment(lib,&quot;ws2_32.lib&quot;)<br><br>本代码在win2k和vc6.0下编译成功~~<br>用法,把这几个文件添加到你的项目中，在WinMain()中添加如下代码:<br>CHTTPPROXY httpproxy;<br>httpproxy.StartProxy(7890);<br>有问题mailto me！ <br><br> <br><img src ="http://www.cppblog.com/niewenlong/aggbug/64561.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-21 02:22 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/21/64555.html#64561#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>