【代码积累】TCP server

来源:互联网 发布:反渗透 纯水机 知乎 编辑:程序博客网 时间:2024/06/17 15:59
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 JAVAprivate 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 blocke.printStackTrace();}}@Overridepublic void run() {// TODO Auto-generated method stubwhile( true == isRunning ){try {connSocket = serverSocket.accept();if( null != connSocket ){//handle connect in newly constructed threadFuture<?> 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 blocke.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;}@Overridepublic 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 blocke1.printStackTrace();}}// TODO Auto-generated method stub//get info from the socket via streamwhile( !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 successString received = new String(recvbuffer,0,cnt);  /*注意使用有效的数据长度,而不是整个buffer的长度创建string,避免乱码*///logger.log(Level.INFO, "Received: "+received);//send an echo as soon as possibleString 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 blocke.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 possibleString 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 blocke.printStackTrace();try {connSocket.close();} catch (IOException e1) {// TODO Auto-generated catch blocke1.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保存每次读取的stringlogger.log(Level.INFO, "Server received:"+line);}}} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}} else {logger.log(Level.INFO, "Socket is null! Stop reading!");isRunning = false;}}}}}

原创粉丝点击