Java Socket服务器与客户端实例

    本实例采用生产者/消费者模式进行设计,源码中包含了详细的注释。为了方便测试将服务器放在一个Servlet里面启动,浏览器访问该Servlet时启动服务器监听

1. 服务器源码

package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
//此处使用Servlet方式进行编写,方便进行测试,在应用启动的时候就打开一个线程去监听客户端请求
public class ServerServlet implements Servlet {
    public void init(ServletConfig arg0) throws ServletException {
        Handler handler = new Handler();
        Thread thread = new Thread(handler);
        thread.start();
    }
    //客户端连接线程池
    private ExecutorService executor = Executors.newFixedThreadPool(20);
    //客户端请求处理线程池,此处要注意客户请求是否有先后顺序、共享资源
    private ExecutorService bizExecutor = Executors.newFixedThreadPool(1);
    //创建一个阻塞队列保存客户的请求信息
    public LinkedBlockingQueue<ClientInfo> queue = new LinkedBlockingQueue<ClientInfo>();
    //保存客户请求信息实体
    class ClientInfo{
        private String xml;
        private String ip;
        public ClientInfo(String xml, String ip){
            super();
            this.xml = xml;
            this.ip = ip;
        }
        public String getXml() {
            return xml;
        }
        public void setXml(String xml) {
            this.xml = xml;
        }
        public String getIp() {
            return ip;
        }
        public void setIp(String ip) {
            this.ip = ip;
        }
    }
    //服务器线程,监听客户端请求
    class Handler implements Runnable{
        public void run(){
            //开启一个业务处理线程,处理客户端的请求
            bizExecutor.submit(new BizHandler());
            ServerSocket server = null;
            try{
                server = new ServerSocket(11480);
            } catch(Exception e){
                e.printStackTrace();
            }
            if(server != null){
                System.out.println("服务器端口已打开");
                while(true){
                    try{
                        Socket socket = server.accept();
                        //开启一个与客户端连接的线程
                        ProgressThread proThread = new ProgressThread(socket);
                        executor.submit(proThread);
                    } catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    //客户端连接线程
    class ProgressThread implements Runnable{
        private Socket socket;
        public ProgressThread(Socket socket){
            super();
            this.socket = socket;
        }
        public void run(){
            try{
                StringBuilder sb = new StringBuilder();
                InputStream is = socket.getInputStream();
                BufferedReader in = new BufferedReader(new InputStreamReader(is,"utf-8"));
                String line = null;
                //以行为单位读取数据,长连接时若无换行符将不能读出数据,只能在socket关闭时一次性得到数据
                while((line = in.readLine()) != null){
                    if(line.trim().endsWith("/xml>")){
                        sb.append(line);
                        if(sb != null && !"".equals(sb.toString().trim())){
                            queue.put(new ClientInfo(sb.toString(),this.socket.getLocalAddress().toString()));
                        }
                        sb = new StringBuilder();
                    } else {
                        sb.append(line);
                    }
                }
//                //没有换行符的读取方式,需捕获connect reset异常
//                while (true){
//                    try{
//                        char[] ch = new char[1024];
//                        int n = in.read(ch);
//                        System.out.println(new String(ch, 0, n));
//                    } catch(Exception e){
//                        System.out.println("客户端连接已关闭");
//                        break;
//                    }
//                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    //客户请求信息处理线程
    class BizHandler implements Runnable{
        public void run(){
            while(true){
                try{
                    //取出阻塞队列中的信息处理
                    final ClientInfo info = queue.poll();
                    if(info == null){
                        Thread.sleep(5000);
                    } else {
                        writeData(info.getXml(),info.getIp());
                    }
                } catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
        public void writeData(String str1, String str2){
            System.out.println(str1);
            System.out.println(str2);
        }
    }
    public void destroy() {
    }
    public ServletConfig getServletConfig() {
        return null;
    }
    public String getServletInfo() {
        return null;
    }
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
    }
}
2. 测试客户端

package test;
import java.io.OutputStream;
import java.net.Socket;
public class ClientTest {
    public static void main(String[] args) {
        Socket socket;
        try {
            socket = new Socket("localhost", 11480);
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("<xml>Hello</xml>\r\n".getBytes("utf-8"));
            outputStream.flush();
            System.out.println(socket);
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值