【代码积累】TCP server

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;


public class TCPServer implements Runnable{
	/*绑定监听IP:port
	 * 1、起一个主线程进行监听,采用 thread per request的方式处理请求;
	 * 2、每个请求,回送一个应答*/
	public static final int MAX_THREAD = 10;
	
	private String ip = null;
	private int port = 0;
	private SocketAddress listeningAddress = null;
	private ServerSocket serverSocket = null;
	private Logger logger = Logger.getLogger(this.getClass().getName());  //Use default logger of JAVA
	private Socket connSocket = null;
	private ExecutorService threadpool = Executors.newFixedThreadPool(MAX_THREAD);
	private Map<String,ConnectionInfo> connectionPool = Collections.synchronizedMap(new HashMap<String,ConnectionInfo>());
	
	public volatile boolean isRunning = true;
	
	public TCPServer(String ip,int port) {
		this.ip = ip;
		this.port = port; 
		listeningAddress = new InetSocketAddress(ip, port);
		
		try {
			serverSocket = new ServerSocket(port, 0, ((InetSocketAddress)listeningAddress).getAddress());
			logger.log(Level.INFO, "Server started...listening on "+this.ip+":"+this.port);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
		
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while( true == isRunning )
		{
			try {
				connSocket = serverSocket.accept();
				if( null != connSocket )
				{
					//handle connect in newly constructed thread
					Future<?> future = threadpool.submit(new RequestHandler(connSocket));
					String connectionKey = new String(connSocket.getInetAddress().getHostAddress()+":"+connSocket.getPort());
					connectionPool.put(connectionKey, new ConnectionInfo(future,connSocket));  /*讲连接放入server的连接池,便于后续使用*/
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	
	private class ConnectionInfo {
		public Future<?> future = null;
		public Socket socket = null;
		
		public ConnectionInfo(Future<?> future,Socket socket) {
			this.future = future;
			this.socket = socket;
		}
	}
	
	private class RequestHandler implements Runnable {
		private final int RECV_BUF_LEN = 1024;
		private Socket connSocket = null;
		private InputStream in = null;
		private OutputStream out = null;
		private BufferedInputStream bufin = null;
		private BufferedOutputStream bufout = null;
		private boolean isRunning = true;
		private byte[] recvbuffer = new byte[RECV_BUF_LEN];  
		private int handleswitch = 2;
		//recvbuffer := make([]byte,1024,1024)  /*define a slice in golang*/
		//var recvbuffer [1024] byte   /*define an array in golang*/
		
		public RequestHandler(Socket connSocket) {
			this.connSocket = connSocket;
		}
		
		@Override
		public void run() {
			if( null != connSocket ) {
				try {
					in = connSocket.getInputStream();
					out = connSocket.getOutputStream();
					
					bufin = new BufferedInputStream(connSocket.getInputStream());
					//bufout = new BufferedOutputStream(connSocket.getOutputStream(),200);
					/*如果创建的时候不指定buffer大小,默认是8K;如果buffer较小,buffer满的时候会自动执行flush;stream关闭的时候,会自动flush*/
					bufout = new BufferedOutputStream(connSocket.getOutputStream());
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				
				
			}
			
			// TODO Auto-generated method stub
			//get info from the socket via stream
			while( !Thread.currentThread().isInterrupted() && true == isRunning) {
				if( null != connSocket ) {
					if( handleswitch == 1 ) {
						//第一种方式,通过传统的stream方式读取
						if( null != in && null != out)
						{
							// in.read(); /*返回stream中的下一个byte,作为int类型返回,如果stream到达末尾,则返回-1*/
							try {
								int cnt = in.read(recvbuffer);
								if( cnt > 0) {
									//recv success
									String received = new String(recvbuffer,0,cnt);  /*注意使用有效的数据长度,而不是整个buffer的长度创建string,避免乱码*/
									//logger.log(Level.INFO, "Received: "+received);
									
									//send an echo as soon as possible
									String response = new String("I'm the server,received your message:"+received);
									logger.log(Level.INFO, response);
									out.write(response.getBytes());
								}
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
								//send an event to TCPSever to notify it to handle connection failure.
								isRunning = false;
							}
						}
					} else if( handleswitch == 2 ) {
						//第二种方式,使用bufferedstream的方式读取
						if( bufin != null && bufout != null ) {
							try {
								int cnt = bufin.read(recvbuffer);  //底层是调用InputStream的read逐个字节读到buffer里的
								if( cnt > 0 ) {
									String received = new String(recvbuffer,0,cnt);  /*注意使用有效的数据长度,而不是整个buffer的长度创建string,避免乱码*/
									//logger.log(Level.INFO, received);
									
									//send an echo as soon as possible
									String response = new String("I'm the server,received your message:"+received);
									logger.log(Level.INFO, response);
									
									bufout.write(response.getBytes());
									bufout.flush();
								}
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
								try {
									connSocket.close();
								} catch (IOException e1) {
									// TODO Auto-generated catch block
									e1.printStackTrace();
								}
								isRunning = false;
							}
						}
						
						/*综上:个人认为,bufferedstream的意义,在发送的时候大于接收的时候,从源码看到,接收的时候,基本还是调用底层的read逐个字节读的;
						 * 在发送端,业务线程可以不断把数据往buffer里填,直到需要发送或者buffer满的时候,调用或触发flush将数据提交给OS(并非提交给
						 * 物理设备,如网卡),这样在某些场景下,业务线程不必每填一次数据都write一把,提高了效率。*/
					} else if( handleswitch == 3 ) {
						//第三种方式,使用reader/writer方式读取
						try {
							//从字节流到字符流再到文本
							BufferedReader br = new BufferedReader(new InputStreamReader(connSocket.getInputStream(), "UTF-8"));
							if( null != br ) {
								String line = null;
								//BufferedReader 有几种读的方式:1、逐个字符读取;2、将字符流顺序读取到指定的缓存中;3、逐行读取(以换行符为准)
								while( null != ( line = br.readLine()) ) {    
									//readline 以换行符、字符串结束符为准
									//如果读不到行结束,该调用会阻塞并一直读取,直到字符流结束,内部用StringBuffer保存每次读取的string
									logger.log(Level.INFO, "Server received:"+line);
								}
							}
						} catch (UnsupportedEncodingException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					
					
				} else {
					logger.log(Level.INFO, "Socket is null! Stop reading!");
					isRunning = false;
				}
			}
		}
		
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值