soket多线程操作服务端及客户端代码

来源:互联网 发布:react.js vue.js 编辑:程序博客网 时间:2024/05/23 15:53
 package posserver;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
 
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
 
import posserver.ConfigProperties;
import posserver.Handler;
import posserver.InitProxool;
 
/**
 * @author Linuxok 2008-05-04 Socket线程池服务端
 */
public class MultiThreadServer {
 
    static Logger logger = Logger.getLogger(MultiThreadServer.class.getName());
 
    private int port = ConfigProperties.getPort(); // 获取服务器监听端口; // 默认服务器端口
 
    private ServerSocket serverSocket;
 
    private ExecutorService pool; // 线程池
 
    private final int POOL_SIZE = 5; // 单个CPU线程池大小
 
    private int portForShutdown = ConfigProperties.getPortForShutdown(); // 用于监听关闭服务器命令的端口
 
    private ServerSocket serverSocketForShutdown;
 
    private boolean isShutdown = false; // 服务器是否已经关闭
 
    private String shutdownStr = "402882a119b650c90119b65164790001"; // 关闭服务用的字符串
 
    /***************************************************************************
     * 关闭服务器的线程 ---- begin
     */
    private Thread shutdownThread = new Thread() { // 负责关闭服务器的线程
 
        public void start() {
 
            this.setDaemon(true); // 设置为守护线程(也称为后台线程)
 
            super.start();
 
        }
 
        public void run() {
 
            while (!isShutdown) {
 
                Socket socketForShutdown = null;
 
                try {
 
                    socketForShutdown = serverSocketForShutdown.accept();
 
                    BufferedReader br = new BufferedReader(
 
                    new InputStreamReader(socketForShutdown.getInputStream()));
 
                    String command = br.readLine();
 
                    if (command.equals(shutdownStr)) {
 
                        long beginTime = System.currentTimeMillis();
 
                        socketForShutdown.getOutputStream().write(
                                "服务器正在关闭/r/n".getBytes());
 
                        isShutdown = true;
 
                        /*
                         * 请求关闭线程池
                         *  
                         * 线程池不再接收新的任务,但是会继续执行完工作队列中现有的任务
                         *  
                         */
                        try {
                            pool.shutdown();
                            // 等待关闭线程池,等待的超时时间为60秒
                            // while (!pool.isTerminated())
 
                            if (!pool.isTerminated())
                                pool.awaitTermination(60, TimeUnit.SECONDS);
 
                            pool.shutdownNow();
                            serverSocket.close(); // 关闭与Client客户通信的ServerSocket
 
                            long endTime = System.currentTimeMillis();
 
                            socketForShutdown
                                    .getOutputStream()
                                    .write(
                                            ("服务器已经关闭," +
 
                                            "关闭服务器用了" + (endTime - beginTime) + "毫秒/r/n")
                                                    .getBytes());
                            logger.info("服务器关闭!");
                        } catch (InterruptedException e) {
                            pool.shutdownNow();
                            // Preserve interrupt status
                            Thread.currentThread().interrupt();
                            logger.error("关闭pool,serverSocket.close()出错!");
                        } finally {
                            try {
                                if (socketForShutdown != null)
                                    socketForShutdown.close();
                                if (serverSocketForShutdown != null)
                                    serverSocketForShutdown.close();
                            } catch (Exception e) {
                                logger
                                        .error("socketForShutdown,serverSocketForShutdown 关闭出错!"
                                                + e.getMessage());
                            }
 
                        }
                    } else {
 
                        socketForShutdown.getOutputStream().write(
                                "错误的命令/r/n".getBytes());
 
                        socketForShutdown.close();
 
                    }
 
                } catch (IOException e) {
                    logger.error("shutdownThread.run()出错!");
                }
            }
        }
    };
 
    /*
     * 关闭服务器的线程 ---- end
     * ****************************************************************************************************
     */
 
    public MultiThreadServer() throws IOException {
 
        serverSocket = new ServerSocket(port);
 
        // serverSocket.setSoTimeout(60000); // 设定等待客户连接的超过时间为60秒
 
        serverSocketForShutdown = new ServerSocket(portForShutdown);
 
    }
 
    // 启动socket连接池
    public void service() {
 
        while (!isShutdown) {
            Socket server = null;
            try {
                // 接收客户连接,只要客户进行了连接,就会触发accept();从而建立连接
                server = serverSocket.accept();
                server.setSoTimeout(60000); // 把等待客户发送数据的超时时间设为60秒
                pool.execute(new Handler(server));
            } catch (SocketTimeoutException ee) {
                // 不必处理等待客户输入出现的超时异常
            } catch (RejectedExecutionException e) {
                try {
 
                    if (server != null)
                        server.close();
 
                } catch (IOException x) {
                    logger.error("关闭socke server.close()失败" + x.getMessage());
                }
 
                return;
            } catch (SocketException e) {
 
                // 如果是由于在执行serverSocket.accept()方法时,
 
                // ServerSocket被ShutdownThread线程关闭而导致的异常,就退出service()方法
                if (e.getMessage().indexOf("socket closed") != -1)
                    return;
 
            } catch (IOException e) {
                logger.error("service()出错" + e.getMessage());
            }
        }
 
    }
 
    // 启动服务的方法
    public void start() {
 
        // Runtime的availableProcessor()方法返回当前系统的CPU数目.
        int poolCount = Runtime.getRuntime().availableProcessors() * POOL_SIZE;
        logger.info("正在启动创建Socket线程池!");
        pool = Executors.newFixedThreadPool(poolCount); // 创建线程池
 
        shutdownThread.start(); // 启动负责关闭服务器的线程
        
        logger.info("正在启动proxool数据库连接池服务!");
        new InitProxool(); // 启动数据库连接池服务
 
        logger.info("Socket服务器启动,监听端口为 :" + port);
 
        logger.info("Socket线程池大小为 :" + poolCount);
 
        this.service(); // 启动socket连接池
 
    }
 
    public static void main(String[] args) throws IOException {
        String progDir = System.getProperty("user.dir"); // 取得执行程序当前路径
        PropertyConfigurator.configure(progDir
                + ConfigProperties.getLog4jConfig()); // 取得log4j的配制文件
        new MultiThreadServer().start();
    }
}
------------------------------------------------------------------------------------------------------------
package posserver;
 
import java.util.Properties;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import org.apache.log4j.Logger;
 
/**
 * @author Linuxok
 * 
 * 2008-05-07
 * 
 * 读取properties类型的配制文件
 * 
 */
public class ConfigProperties {
 
    static Logger logger = Logger.getLogger(ConfigProperties.class.getName());
 
    private static final String filename = "/conf/config.properties";
 
    private static String progDir = System.getProperty("user.dir"); // 取得执行程序当前路径
 
    //取得启动服务时监听的端口
    public static int getPort() {
        int result = 5000; // 如果读取文件失败,默认打开此端口
        InputStream in = null;
 
        /*
         * getClass().getResourceAsStream("/server.properties"); //类加载器
         * 
         * 如:c:/temp/mytest/Test.class package mytest; public class Test{...}
         * 
         * Test.class.getResourceAsStream(str);
         * 
         * str="/db.properties" 则 db.properties 放在 c:/temp下 str="db.properties"
         * 则 db.properties 放在c:/temp/mytest下
         * 
         */
 
        Properties p = new Properties();
        try {
            in = new FileInputStream(progDir + filename);
            p.load(in);
        } catch (Exception e) {
            logger.error("getPort() p.load()出错了! " + e.getMessage());
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                logger.error("getIntParameter() is error! " + e.getMessage());
            }
        }
        String port = p.getProperty("port");
        if (port != null)
            result = Integer.parseInt(port);
        return result;
    }
 
    //取得关闭服务用端口
    public static int getPortForShutdown() {
        int result = 5001; // 如果读取文件失败,默认打开此端口
        InputStream in = null;
        Properties p = new Properties();
        try {
            in = new FileInputStream(progDir + filename);
            p.load(in);
        } catch (Exception e) {
            logger.error("getPort() p.load()出错了! " + e.getMessage());
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                logger
                        .error("getPortForShutdown() is error! "
                                + e.getMessage());
            }
        }
        String port = p.getProperty("portForShutdown");
        if (port != null)
            result = Integer.parseInt(port);
        return result;
    }
 
    public static String getLog4jConfig() {
        InputStream in = null;
        Properties p = new Properties();
        try {
            in = new FileInputStream(progDir + filename);
            p.load(in);
        } catch (Exception e) {
            logger.error("getLog4jConfig() p.load()出错了! " + e.getMessage());
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                logger
                        .error("getLog4jConfig() throw error! "
                                + e.getMessage());
            }
        }
        return p.getProperty("log4j");
    }
     
    //读取proxool数据库连接池配制文件
    public static String getProxoolXml() {
        InputStream in = null;
        Properties p = new Properties();
        try {
            in = new FileInputStream(progDir + filename);
            p.load(in);
        } catch (Exception e) {
            logger.error("getProxoolXml() p.load()出错了! " + e.getMessage());
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                logger
                        .error("getProxoolXml() throw error! "
                                + e.getMessage());
            }
        }
        return p.getProperty("proxoolXml");
    }
    /*
     * public static void main(String[] args) { ConfigProperties cp = new
     * ConfigProperties(); System.out.println(cp.getPort("portForShutdown")); }
     */
}
-------------------------------------------------------------------------------------------------------
config.properties配制文件内容:
##  服务器端口号
port=5000
 
##  关闭服务器用端口号
portForShutdown=5001
 
## log4j日志配制文件
log4j=/conf/log4j.properties
 
## proxool数据库连接池配制文件
proxoolXml=/conf/proxool.xml
--------------------------------------------------------------------------------------------------------
package posserver;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.*;
 
import org.apache.log4j.Logger;
 
import protocol.Agreement;
 
/**
 * @author Linuxok
 * 
 * 2008-05-08
 * 
 * 用于与客户通信的线程,此线程加入 MultiThreadServer的线程池中
 *
 */
public class Handler implements Runnable {
 
    static Logger logger = Logger.getLogger(Handler.class.getName());
 
    private Socket client;
 
    public Handler(Socket socket) {
        this.client = socket;
    }
 
    private PrintWriter getWriter(Socket socket) throws IOException {
        OutputStream socketOut = socket.getOutputStream();
        PrintWriter out = new PrintWriter(socketOut, true);
        return out;
    }
 
    /*
    private BufferedReader getReader(Socket socket) throws IOException {
        InputStream socketIn = socket.getInputStream();
        BufferedReader in = new BufferedReader(new InputStreamReader(socketIn));
        return in;
    }
    */
     
    public void run(){
 
        PrintWriter pw = null;
         
        try {
            int offset = 0;
            byte[] bt = new byte[1000];
            logger.info("New connection accepted " + client.getInetAddress() + ":"
                    + client.getPort());
 
            pw = getWriter(client);
             
            offset = this.client.getInputStream().read(bt);
             
            StringBuffer msg = new StringBuffer("");
            msg.append(new String(bt).trim());
            int maxLen = Integer.parseInt(msg.substring(0, 4), 16);
            while (offset<maxLen) {
                offset += this.client.getInputStream().read(bt);
                msg.append(new String(bt).trim());
            }
            String rMsg = msg.substring(4).substring(0,maxLen);
            logger.info(rMsg);
            Agreement a = new Agreement();
            rMsg = a.doOption(rMsg);
            pw.println(rMsg);
            pw.flush();
        } catch (IOException e) {
            logger.error("Handler.run()线程出错了!等待输入超时" + e.getMessage());
        } finally {
            logger.info("connection " + client.getInetAddress() + ":"
                    + client.getPort() + " has closed");
            try {
                if (client != null)
                    client.close();
            } catch (IOException ex) {
                logger.error("client.close()出错了!" + ex.getMessage());
            }
        }
    }
    /*
    public void run() {
        BufferedReader in = null;
        PrintWriter pw = null;
        try {
            logger.info("New connection accepted " + client.getInetAddress() + ":"
                    + client.getPort());
 
            in = getReader(client);
            pw = getWriter(client);
            String msg = null;
            if ((msg = in.readLine()) != null) {
                pw.println("Server has receive...." + msg);
                pw.flush();
                logger.info(msg);
            }
            while ((msg = in.readLine()) != null) {
                pw.println("Server has receive...." + msg);
                pw.flush();
                if (msg.equals("bye"))
                    break;
 
            }
             
        } catch (IOException e) {
            logger.error("Handler.run()线程出错了!等待输入超时" + e.getMessage());
        } finally {
            logger.info("connection " + client.getInetAddress() + ":"
                    + client.getPort() + " has closed");
            try {
                if (client != null)
                    client.close();
            } catch (IOException ex) {
                logger.error("client.close()出错了!" + ex.getMessage());
            }
        }
 
    }
    */
}
---------------------------------------------------------------------------------------------------
package posserver;
 
//import java.sql.*; 
 
//import org.apache.log4j.PropertyConfigurator;]
 
import org.apache.log4j.Logger;
import org.logicalcobwebs.proxool.configuration.JAXPConfigurator;
 
import posserver.ConfigProperties;
 
public class InitProxool {
 
    private static Logger logger = Logger.getLogger(InitProxool.class.getName());
 
    public InitProxool() {
 
        String progDir = System.getProperty("user.dir");
        String proxoolXml = ConfigProperties.getProxoolXml();
 
        // PropertyConfigurator.configure(progDir+
        // ConfigProperties.getLog4jConfig()); // 取得log4j的配制文件
 
        try {
            JAXPConfigurator.configure(progDir + proxoolXml, false);
             
            logger.info("proxool连接池已启动");
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }
 
    /*
    public static void main(String[] args) {
        new A();
        Connection connection = null;
        try { 
            // Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");
            try {
                connection = DriverManager.getConnection("proxool.mysql");
            } catch (SQLException e) {
                logger.error("Problem getting connection", e);
            }
            if (connection != null) {
                logger.info("Got connection :)");
            } else {
                logger
                        .error("Didn't get connection, which probably means that no Driver accepted the URL");
            }
        } catch (Exception e) {
            logger.error("Couldn't find driver", e);
        } finally {
            try { // Check to see we actually got a connection before we //
                // attempt to close it. if (connection != null) {
                connection.close();
            } catch (SQLException e) {
                logger.error("Problem closing connection", e);
            }
        }
    }
    */
}
----------------------------------------------------------------------------------------------------
关闭服务的客户端代码如下:
package posserver;
 
import java.net.Socket;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.InputStreamReader;
 
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
 
 
/**
 * @author Linuxok
 *
 * 2008-05-04
 *
 * 关闭 MultiThreaServer的客户端程序
 */
public class AdminClient {
     
    static Logger logger = Logger.getLogger(AdminClient.class.getName());
 
    public static void main(String args[]) {
         
        int port = ConfigProperties.getPortForShutdown();
         
        String INetAddress = "localhost";
        Socket socket = null;
        String strForShutdown = "402882a119b650c90119b65164790001/r/n";
 
        String progDir = System.getProperty("user.dir"); // 取得执行程序当前路径
        PropertyConfigurator.configure(progDir + ConfigProperties.getLog4jConfig());  //取得log4j.properties的配制文件
         
        try {
 
            socket = new Socket(INetAddress, port);
 
            // 发送关闭命令
 
            OutputStream socketOut = socket.getOutputStream();
 
            socketOut.write(strForShutdown.getBytes());
 
            // 接收服务器的反馈
 
            BufferedReader br = new BufferedReader(
 
            new InputStreamReader(socket.getInputStream()));
 
            String msg = null;
 
            while ((msg = br.readLine()) != null)
 
                logger.info(msg);
 
        } catch (IOException e) {
 
            logger.error("AdminClient 关闭服务失败! "+e.getMessage());
 
        } finally {
            try {
 
                if (socket != null)
                    socket.close();
 
            } catch (IOException e) {
                logger.error("关闭socket失败! "+e.getMessage());
            }
        }
    }
}
-------------------------------------------------------------------------------------------------------
客户端与服务器通信代码如下:
package posserver;
 
import java.net.*;
import java.io.*;
 
import com.general.FormatDate;
 
public class MyClient {
    static Socket server;
 
    public static void main(String[] args) throws Exception {
        server = new Socket("192.168.2.23", 5000);
        BufferedReader in = new BufferedReader(new InputStreamReader(server
                .getInputStream()));
        PrintWriter out = new PrintWriter(server.getOutputStream());
        String sRespond = "16";
        String terminalId = "000001";
        String seriesId = FormatDate.formatStr("121"," ", 8);
        String huhao = FormatDate.formatStr("12006178"," ", 16);
        String feeMonth = "00000000";
        StringBuffer str = new StringBuffer("");
        str.append(sRespond).append(terminalId).append(seriesId).append(huhao).append(feeMonth);
        str.insert(0, FormatDate.formatStr(Long.toHexString(str.length()),"0", 4));
        try {
            System.out.println("开始发送字符");
            out.println(str);
            out.flush();
            // 接收服务器的反馈
 
            BufferedReader br = new BufferedReader(
 
            new InputStreamReader(server.getInputStream()));
 
            String msg = null;
 
            while ((msg = br.readLine()) != null)
 
                System.out.println(msg);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            out.close();
            server.close();
        }
    }
 
}
原创粉丝点击