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. django 操作数据库--orm(object relation mapping)---models

    思想 django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM). PHP:activerecord Java:Hibernate C#:Ent ...

  2. youtube视频批量下载

    youtube 下载视频脚本: 得到下载列表:download_list var links = document.getElementsByTagName('a'); for(var i =0;i& ...

  3. keystone v3 相关介绍

    1) 涉及到如下几个概念:User.Tenant.Role.Token.http://www.ibm.com/developerworks/cn/cloud/library/1506_yuwz_key ...

  4. 【SpringBoot】SpringBoot 入门示例

    参考资料: http://www.tuicool.com/articles/mqeee2A http://www.cnblogs.com/suncj/p/4065589.html http://spr ...

  5. Response.Redirect()、Server.Execute和Server.Transfer的区别

    1.Response.Redirect(): Response.Redirect方法导致浏览器链接到一个指定的URL. 当Response.Redirect()方法被调用时,它会创建一个应答,应答头中 ...

  6. windows hosts

    2015年6月29日 11:10:56 星期一 windows 的 hosts 文件生效机制 以最前边的为准, 重复的硬解析只有第一次出现的地方生效

  7. 4.js模式-发布-订阅模式

    1. 发布-订阅模式 var observe = (function(){ var events = {}, listen, trigger, remmove; listen = function(k ...

  8. FFmpeg frei0r water 滤镜

    FFmpeg frei0r water 滤镜, 在 linux 环境中很流畅,但在 XP 环境中抛出异常 研究一段时间修改了代码,能在 XP 里跑得动. sample.water.avi water. ...

  9. AIX系统中安装Java6全过程(全部)

    ====================================================   From: GCG TSC pSeries <ibm800p@cn.ibm.com& ...

  10. Aix下如何运行Java程序

    windows下:java -classpath %classpath%;bb.jar;aa.jar [main class]main class是打包的主类,已经指定了主类,可以不输入.另外,IBM ...