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. struts2回显指定的错误信息

     <s:fielderror />  显示全部的 错误消息(用addFieldError方法添加的 )   <s:fielderror>            <s:pa ...

  2. 【架构】MQTT/XMPP/GCM 等参考资料

    https://www.zhihu.com/question/29138530 https://segmentfault.com/q/1010000002598843/a-10200000026014 ...

  3. Strobogrammatic Number

    Strobogrammatic Number I A strobogrammatic number is a number that looks the same when rotated 180 d ...

  4. poj 1011

    http://poj.org/problem?id=1011 这是一道POJ的搜索的题目,最开始确实难以理解,但做过一些搜索的题目后,也没那么难了. 大概题意就是,现在有N根木头,要拼成若干根木头,并 ...

  5. cf219d

    树形dp #include <cstdio> #include <vector> using namespace std; #define D(x) const int INF ...

  6. mysql格式化整数类型时间生成年月日时分秒格式(long或string接收)

    数据库格式: 数据库mysql语句: FROM_UNIXTIME( s.timemodified, '%Y-%m-%d %h:%i:%s' ) 生成结果: 测试sql为: SELECT *, FROM ...

  7. 利用冒泡对List排序

    SysMenu是List集合中的类型,在这是一个菜单实体. public List<SysMenu> selfMenuSort(List<SysMenu> list) { fo ...

  8. NIS 报错No such map passwd.byname. Reason: Can't bind to server which serves this domain

    在NIS—client端使用命令:ypcat passwd ,把错如上题, 原因:client端ypbind服务未启动解决方法:当然是启动ypbind了,命令:service ypbind start ...

  9. python安装paramiko模块

    一.简介 paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 由于使用的是python这样的能够跨平台运行的语言,所以所有python支 ...

  10. mysql常用函数整理

    一.数学函数 数学函数主要用于处理数字,包括整型.浮点数等. ABS(x) 返回x的绝对值 ) -- 返回1 CEIL(x),CEILING(x) 返回大于或等于x的最小整数 SELECT CEIL( ...