本来意图是想写个工具放到服务器里代理一下上秋秋的。
没想到N台(电信/联通/移动)的服务器都把端口全封了。
所以以下代码是在本地测试代理网页访问通过。
说下思路再上代码及下载:
其实一句话就是:产生两个Soket,一个负责接收请求和回发请求,另一个负责中转的去请求和接收。
重点一句话就是:每个请求产生一个线程处理,处理时关键是的延时处理(不然数据接收不全)。
现在上代码,Proxy自定义类:
Proxy
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;//by 路过秋天
namespace TCPProxy
{
public class Proxy
{
Socket clientSocket;//接收和返回
Byte[] read = null;//存储来自客户端请求数据包
Byte[] recvBytes = null;//存储中转请求返回的数据
public Proxy(Socket socket)
{
clientSocket = socket;
recvBytes = new Byte[1024 * 1024];
clientSocket.ReceiveBufferSize = recvBytes.Length;
clientSocket.SendBufferSize = recvBytes.Length;
clientSocket.SendTimeout = 10000;
clientSocket.ReceiveTimeout = 10000;
}
public void Run()
{
#region 获取客户端请求数据
string clientmessage = "";
read = new byte[clientSocket.Available];
int bytes = ReadMessage(read, ref clientSocket, ref clientmessage);
if (bytes == 0)
{
Write("读取不到数据!");
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
return;
}
int port = 80;
string url = GetUrl(clientmessage, port);
#endregion
try
{
#region IP解析获取
IPHostEntry IPHost= Dns.GetHostEntry(url);
Write("-----------------------------请求开始---------------------------");
Write("http://" + IPHost.HostName);
string[] aliases = IPHost.Aliases;
IPAddress[] address = IPHost.AddressList;//解析出要访问的服务器地址
Write("IP地址:" + address[0]);
#endregion
#region 创建中转Socket及建立连接
IPEndPoint ipEndpoint = new IPEndPoint(address[0], port);
Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建连接Web服务器端的Socket对象
IPsocket.Connect(ipEndpoint);
//Socket连Web接服务器
if (IPsocket.Connected)
{
Write("Socket 正确连接!");
}
#endregion
#region 发送中转请求
IPsocket.Send(read, 0);
Write("发送字节:" + read.Length);
#endregion
#region 接收中转请求数据
int length = 0, count = 0;
do
{
length = IPsocket.Receive(recvBytes, count, IPsocket.Available, 0);
count = count + length;
Write("正在接收数据..." + length);
System.Threading.Thread.Sleep(100);//关键点,请求太快数据接收不全
}
while (IPsocket.Available > 0);
#endregion
#region 关闭中转请求Socket
IPsocket.Shutdown(SocketShutdown.Both);
IPsocket.Close();
#endregion
#region 将中转请求收到的数据发回客户端
clientSocket.Send(recvBytes, 0, count, 0);
Write("正在返回数据..." + count);
#endregion
#region 结束请求,关闭客户端Socket
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
recvBytes = null;
Write("完成,已关闭连接...");
Write("-----------------------------请求结束---------------------------");
#endregion
}
catch (Exception err)
{
System.Console.WriteLine(err.Message + err.Source);
}
}
//从请求头里解析出url和端口号
private string GetUrl(string clientmessage, int port)
{
int index1 = clientmessage.IndexOf(' ');
int index2 = clientmessage.IndexOf(' ', index1 + 1);
if ((index1 == -1) || (index2 == -1))
{
throw new IOException();
}
string part1 = clientmessage.Substring(index1 + 1, index2 - index1).Trim();
string url = string.Empty;
if (!part1.Contains("http://"))
{
part1 = "http://" + part1;
}
Uri uri = new Uri(part1);
url = uri.Host;
port = uri.Port;
return url;
}
//接收客户端的HTTP请求数据
private int ReadMessage(byte[] readByte, ref Socket s, ref string clientmessage)
{
int bytes = s.Receive(readByte, readByte.Length, 0);
clientmessage = Encoding.ASCII.GetString(readByte);
return bytes;
}
private void Write(string msg)
{
// return;
System.Console.WriteLine(msg);
}
}
}
在控制台里调用:
代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Net.Sockets;
using System.Threading;
namespace TCPProxy
{
class Program
{
static void Main(string[] args)
{
Listen(8989);
}
static void Write(string msg)
{
Console.WriteLine(msg);
}
static void Listen(int port)
{
Write("准备监听端口:" + port);
TcpListener tcplistener = new TcpListener(port);
try
{
tcplistener.Start();
}
catch
{
Write("该端口已被占用,请更换端口号!!!");
ReListen(tcplistener);
}
Write("确认:y/n (yes or no):");
string isOK = Console.ReadLine();
if (isOK == "y")
{
Write("成功监听端口:" + port);
//侦听端口号
Socket socket;
while (true)
{
socket = tcplistener.AcceptSocket();
//并获取传送和接收数据的Scoket实例
Proxy proxy = new Proxy(socket);
//Proxy类实例化
Thread thread = new Thread(new ThreadStart(proxy.Run));
//创建线程
thread.Start();
System.Threading.Thread.Sleep(10);
//启动线程
}
}
else
{
ReListen(tcplistener);
}
}
static void ReListen(TcpListener listener)
{
if (listener != null)
{
listener.Stop();
listener = null;
}
Write("请输入监听端口号:");
string newPort = Console.ReadLine();
int port;
if (int.TryParse(newPort, out port))
{
Listen(port);
}
else
{
ReListen(listener);
}
}
}
}
本人测试:
在打开IE-》工具->Internet选项->链接->局域网设置->代理连接-》输入IP和端口号
访问网站,查看控制台输出消息,页面访问正常,测试通过。
本来想测试下QQ代理,无奈本地已被封,服务器也没端口可用。有空回家再测了。
提供代码下载