单线程的代理服务器

import java.io.*;
import java.net.*;
/**
 * 这个类实现了一个简单的单线程的代理服务器
 */
public class SimpleProxyServer {
 /** 主函数解析参数并把参数传递给runServer */
 public static void main(String[] args) throws IOException {
  try {
   // 检查参数的个数
   if (args.length != 3)
    throw new IllegalArgumentException("Wrong number of args.");
   // 获得命令行参数: 我们要代理的主机和端口
   String host = args[0];
   int remoteport = Integer.parseInt(args[1]);
   int localport = Integer.parseInt(args[2]);
   // 显示开始信息
   System.out.println("Starting proxy for " + host + ":" +
    remoteport + " on port " + localport);
   // 开始运行这个服务器
   runServer(host, remoteport, localport); // 永不返回
  }
  catch (Exception e) {
   System.err.println(e);
   System.err.println("Usage: java SimpleProxyServer " +
    "<host> <remoteport> <localport>");
  }
 }

 /**
  * 这个方法运行一个单线程的代理服务器,它在指定的本地端口上
  * 代理一个主机上的远程端口。它用不返回。
  */
 public static void runServer(String host, int remoteport, int localport)
  throws IOException {
  // 创建一个ServerSocket来监听连接
  ServerSocket ss = new ServerSocket(localport);
  // 为客户端到服务器和服务器到客户端创建缓冲区
  // 我们指定缓冲区为final,使它能够在下面的匿名类中能够被使用
  // 注意在每个方向上交换量上的假定
  final byte[] request = new byte[1024];
  byte[] reply = new byte[4096];
  // 这是一个用不返回的服务器,故进入一个无限循环
  while(true) {
   // 保持与客户端和与服务器连接的socket的变量
   Socket client = null, server = null;
   try {
    // 等待一个本地端口的连接
    client = ss.accept();
    // 获取客户流,把他们定义成final使得他们在下面的匿名
    // 类中能够被使用
    final InputStream from_client = client.getInputStream();
    final OutputStream to_client = client.getOutputStream();
    // 建立一个与真实服务器的连接
    // 如果我们不能连上服务器,发送一个错误给客户端
    // 取消连接,等待下次连接
    try { server = new Socket(host, remoteport); }
    catch (IOException e) {
     PrintWriter out = new PrintWriter(to_client);
     out.print("Proxy server cannot connect to " + host + ":"+
      remoteport + ":\n" + e + "\n");
     out.flush();
     client.close();
     continue;
    }
    // 获得服务器的流
    final InputStream from_server = server.getInputStream();
    final OutputStream to_server = server.getOutputStream();
    // 创建一个线程读取客户端的请求,把请求传递给服务器,我们不得不
    // 使用一个独立的线程,因为请求和响应是异步的
    Thread t = new Thread() {
     public void run() {
      int bytes_read;
      try {
       while((bytes_read=from_client.read(request))!=-1) {
        to_server.write(request, 0, bytes_read);
        to_server.flush();
       }
      }
      catch (IOException e) {}
      // 客户端关闭了同我们的连接,那么也就关闭了我们与服务器的
      // 连接。这将造成主线程中服务器与客户端之间的循环退出
      try {to_server.close();} catch (IOException e) {}
     }
    };
    // 开始客户端到服务器请求线程的运行
    t.start();
    // 同时,在主线程中,读取服务器的响应,并把它们传递给客户端。这将
    // 与上面提到的客户端到服务器的请求线程并行执行
    int bytes_read;
    try {
     while((bytes_read = from_server.read(reply)) != -1) {
      to_client.write(reply, 0, bytes_read);
      to_client.flush();
     }
    }
    catch(IOException e) {}
    // 服务器关闭同我们的连接,那么我们关闭与客户端的连接
    // 这将使另外一个线程退出
    to_client.close();
   }
   catch (IOException e) { System.err.println(e); }
   finally { // 不管发生什么关闭线程
    try {
     if (server != null) server.close();
     if (client != null) client.close();
    }
    catch(IOException e) {}
   }
  }
 }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值