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. Octopress博客使用

    在C:\DevKit\octopress目录下 执行如下指令 rake preview 打开浏览器 http://localhost:4000/ 重新生成 rake generate 部署 rake ...

  2. mybatis动态SQL - like

    用'%${name}%'可以实现模糊查询,但会放开SQL注入漏洞. <when test="name != null and name!=''"> AND name l ...

  3. 傅里叶变换库FFTW的安装配置(VS2010)

    FFTW是用来计算一维或者多维的离散傅里叶变换,输入可以为实数序列也可以为复数序列的C语言的子函数库,FFTW是免费软件,是作为fft函数库的各种应用的上佳选择. 1. 从网站http://www.f ...

  4. Python类的特点 (1):构造函数与方法

    Python中,类的特点: #encoding:utf-8 class Parent(object): x=1 #x是Parent类的属性(字段) def __init__(self): print ...

  5. 【Networking】go get 失败,代理配置

    推荐VPN: https://vpnso.com/   如果还是有问题,比如: 重新编译Git,使用openssl替换gnutls,方法如下: http://askubuntu.com/questio ...

  6. C#操作txt文件

    目的:txt文件的创建,读写操作 功能:创建一个winform窗体,当文件不存在时可以实现txt文件的创建 效果: 代码: 文件的创建(判断文件是否存在,不存在则创建新的文本文件): private ...

  7. hibernate xx(tableName) is not mapped

    数据库中表名是:book,数据库表名不区分大小写的 之后我在hibernate 使用book, String sql="from book"; Query query=sessio ...

  8. 数据结构——二叉查找树、AVL树

    二叉查找树:由于二叉查找树建树的过程即为插入的过程,所以其中序遍历一定为升序排列! 插入:直接插入,插入后一定为根节点 查找:直接查找 删除:叶子节点直接删除,有一个孩子的节点删除后将孩子节点接入到父 ...

  9. 【QT】自己生成ui加入工程

    在三个月前 我就在纠结 C++ GUI Qt 4编程这本书中2.3节 快速设计对话框这一段. 按照书上的做没有办法生成能够成功运行的程序. 这两天又折腾了好久,终于成功了. 注意事项: 1. 我之前装 ...

  10. ocx文件转换成C#程序引用的DLL

    将ocx文件转换成C#程序引用的DLL文件的办法  将ocx文件转换成C#程序引用的DLL文件的办法,需要的朋友可以参考一下  1.打开VS2008或VS2010命令提示符(此例用VS2008) 将o ...