socket 层面实现代理服务器

首先是简一个简单的socket客户端和服务器端的例子

建立连接

Socket client = new Socket(AddressFamily.InterNetwork,                SocketType.Stream, ProtocolType.Tcp);            // Connect to the remote endpoint.            client.BeginConnect( remoteEP,                 new AsyncCallback(ConnectCallback), client);

这里采用回调的api,当然现在有各种异步的模式选择问题,这里先不管。

private static void ConnectCallback(IAsyncResult ar) {        try {            // Retrieve the socket from the state object.            Socket client = (Socket) ar.AsyncState;            // Complete the connection.            client.EndConnect(ar);            Console.WriteLine("Socket connected to {0}",                client.RemoteEndPoint.ToString());            // Signal that the connection has been made.            connectDone.Set();        } catch (Exception e) {            Console.WriteLine(e.ToString());        }    }

回调的蛋疼指出就在于次,我们把socket对象以参数的形式传递过来,然后完成连接。

private static void Send(Socket client, String data) {        // Convert the string data to byte data using ASCII encoding.        byte[] byteData = Encoding.ASCII.GetBytes(data);        // Begin sending the data to the remote device.        client.BeginSend(byteData, 0, byteData.Length, 0,            new AsyncCallback(SendCallback), client);    }

这里我们开始发送数据,发送不需要建立缓冲区。

 private static void SendCallback(IAsyncResult ar) {        try {            // Retrieve the socket from the state object.            Socket client = (Socket) ar.AsyncState;            // Complete sending the data to the remote device.            int bytesSent = client.EndSend(ar);            Console.WriteLine("Sent {0} bytes to server.", bytesSent);            // Signal that all bytes have been sent.            sendDone.Set();        } catch (Exception e) {            Console.WriteLine(e.ToString());        }    }

发送完毕,统计下总共发送了多少字节。

服务器端按照缓冲区大小收取数据:

private static void ReceiveCallback( IAsyncResult ar ) {        try {            // Retrieve the state object and the client socket             // from the asynchronous state object.            StateObject state = (StateObject) ar.AsyncState;            Socket client = state.workSocket;            // Read data from the remote device.            int bytesRead = client.EndReceive(ar);            if (bytesRead > 0) {                // There might be more data, so store the data received so far.            state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));                // Get the rest of the data.                client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,                    new AsyncCallback(ReceiveCallback), state);            } else {                // All the data has arrived; put it in response.                if (state.sb.Length > 1) {                    response = state.sb.ToString();                }                // Signal that all bytes have been received.                receiveDone.Set();            }        } catch (Exception e) {            Console.WriteLine(e.ToString());        }    }

这里我们其实不停的自我递归调用,直到取完所有的数据。

所谓的代理只不过是在两套客户端和服务器端的组合

本地服务收到请求后连接远程代理服务器

                IPAddress ipAddress;                bool parsed = IPAddress.TryParse(server.server, out ipAddress);                if (!parsed)                {                    IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server);                    ipAddress = ipHostInfo.AddressList[0];                }                IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port);                remote = new Socket(ipAddress.AddressFamily,                    SocketType.Stream, ProtocolType.Tcp);                remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);                // Connect to the remote endpoint.                remote.BeginConnect(remoteEP,                    new AsyncCallback(ConnectCallback), null);

在连接的回调函数里面判断一下是不是socket5 协议

int bytesRead = _firstPacketLength;                if (bytesRead > 1)                {                    byte[] response = { 5, 0 };                    if (_firstPacket[0] != 5)                    {                        // reject socks 4                        response = new byte[] { 0, 91 };                        Console.WriteLine("socks 5 protocol error");                    }                    connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null);                }                else                {                    this.Close();                }

接下去开始代理

private void StartPipe(IAsyncResult ar)        {            if (closed)            {                return;            }            try            {                connection.EndReceive(ar);                remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0,                    new AsyncCallback(PipeRemoteReceiveCallback), null);                connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0,                    new AsyncCallback(PipeConnectionReceiveCallback), null);            }            catch (Exception e)            {                Logging.LogUsefulException(e);                this.Close();            }        }

这里面的逻辑一定要清晰,localsocket数据通过remotesocket发送到远程服务器,remotesocket数据通过localsocket发送会应用程序。

最终数据发给应用程序之前,再进行一次解密的操作。

int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0)
{
int bytesToSend;
lock (encryptionLock)
{
if (closed)
{
return;
}
encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend);
}
remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null);
}
else
{
remote.Shutdown(SocketShutdown.Send);
remoteShutdown = true;
CheckClose();
}

远程服务器上的程序

相应你能够自己完成这个步骤,因为远程和你本机没有什么本质差别,都是一层socket的转发而已,不需要局限于.net,可以用python或者golang写。不多说了,博主要去门口收快递了。

.net socket 层面实现代理服务器的更多相关文章

  1. 客户端Socket

    导语 java.net.Socket类是JAVA完成客户端TCP操作的基础类.其他建立TCP网络连接的类(如URL,URLConnection和EditorPane)最终会调用这个类的方法.这个类本身 ...

  2. 网络编程:基于C语言的简易代理服务器实现(proxylab)

    本文记录了一个基于c socket的简易代理服务器的实现.(CS:APP lab 10 proxy lab) 本代理服务器支持keep-alive连接,将访问记录保存在log文件. Github: h ...

  3. 【Python】socket模块应用

    [Socket] 本文记录了一些socket模块的简单应用,对于具体原理还没来得及深究. ■ 利用socket模块进行端口连接验证和扫描 在linux中常用nc命令来进行远端端口是否开放的验证.但是这 ...

  4. 正确理解这四个重要且容易混乱的知识点:异步,同步,阻塞,非阻塞,5种IO模型

    本文讨论的背景是Linux环境下的network IO,同步IO和异步IO,阻塞IO和非阻塞IO分别是什么 概念说明 在进行解释之前,首先要说明几个概念: - 用户空间和内核空间 - 进程切换 - 进 ...

  5. Tomcat一个BUG造成CLOSE_WAIT

    之前应该提过,我们线上架构整体重新架设了,应用层面使用的是Spring Boot,前段日子因为一些第三方的原因,略有些匆忙的提前开始线上的内测了.然后运维发现了个问题,服务器的HTTPS端口有大量的C ...

  6. SSH ProxyCommand

    简单的说就是SSH层面的代理服务器,实现通过跳板机执行SSH相关命令到目标机器的代理服务.

  7. HTTP的长连接和短连接——Node上的测试

        本文主要从实践角度介绍长.短连接在TCP层面的表现,借助Node.JS搭建后台服务,使用WinHTTP.Ajax做客户端请求测试,最后简单涉及WebSocket.     关键字:长连接.短连 ...

  8. 转-HttpClient4.3 连接管理

    转 http://www.yeetrack.com/?p=782 2.1.持久连接 两个主机建立连接的过程是很复杂的一个过程,涉及到多个数据包的交换,并且也很耗时间.Http连接需要的三次握手开销很大 ...

  9. [转]七天学会NodeJS

    转:http://nqdeng.github.io/7-days-nodejs/ NodeJS基础 什么是NodeJS JS是脚本语言,脚本语言都需要一个解析器才能运行.对于写在HTML页面里的JS, ...

随机推荐

  1. [转]Unchecked Exception 和 Checked Exception 比较

    Throwable类是所有异常的始祖,它有两个直接子类Error / Exception:   Error仅在Java虚拟机中发生动态连接失败或其它的定位失败的时候抛出一个Error对象.一般程序不用 ...

  2. QQ登录类

    2015-3-31 22:02:09 (同一套代码, pc端不能登录, 但是, 手机和平板都可以正常登录.....) 1. 首先是库文件, 登录->授权->token->openid ...

  3. 1.SpringMVC的简介和环境搭建

    SpringMVC的简介: SpringMVC 和 Struts一样是一个MVC框架,和Spring无缝连接,和struts2类似, Spring MVC属于SpringFrameWork的后续产品, ...

  4. java 入门 第三季1

    异常和异常体系 java异常体系 throwable:error:线程死锁,内存溢出 excepiton:rumtimeException运行时异常:非检查异常 检查异常:文件异常IOExceptio ...

  5. java中方法参数的一些总结(1)

    1.问题说明        在C++中,函数调用时有传值调用和传址调用两种方式,但在Java中只有传值调用一种方式.Java中的方法参数为那几种基本数据类型的情况跟C++中一样,传入的只是变量的拷贝. ...

  6. php数据访问(修改)

    修改:跟添加相似,需要显示默认值 先嵌入php代码  查询数据库 $code = $_GET["c"]; $db = new MySQLi("localhost" ...

  7. SlimDX.dll安装之后所在位置

    C:\Windows\Microsoft.NET\assembly\GAC_64\SlimDX\v4.0_4.0.13.43__b1b0c32fd1ffe4f9\SlimDX.dll

  8. VS中新建类

    通常我们在VS中添加类,比如要声明一个car的类 我们通常在新建的时候会写成CCar,虽然新建出来的文件的名词是car,但是我们使用这个类来声明一个类的时候, 是CCar car; 如果新建类写成Ca ...

  9. Swift - 文件目录路径获取及数据储存(Home目录,文档目录,缓存目录)

    iOS应用程序只能在自己的目录下进行文件的操作,不可以访问其他的存储空间,此区域被称为沙盒.   应用沙盒结构分析 1.应用程序包:包含了所有的资源文件和可执行文件 2.Documents:保存应用运 ...

  10. JDBC之SqlHelper

    SqlHelper工具类如下: import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.Resul ...