Web项目集成Socket多线程通信,多客户端通信

Web项目集成Socket多线程通信,多客户端通信

ps:一个服务端面对多可客户端

需要写三个基本的类
  • ServerListener:跟随web初始化创建服务端socket
  • ServerThread:开启监听端口
  • ServerOperate:处理数据
1、ServerListener
public class ServerListener implements ServletContextListener {
    ServerThread serverThread;
    
    //web容器初始化,执行此方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        if(serverThread==null){
            serverThread = new ServerThread();
            serverThread.start();
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        if(serverThread!=null){
            serverThread.closeServer();
        }
    }
}

解释:

  • 如果需要在web启动后就开启ServerSocket监听功能,则需要写一个类去继承ServletContextListener,并实现它的方法contextInitialized,我们则需要在这个方法里重写一下开启ServerSocket监听的方法。
  • 还需要在web.xml里监听一下路径才可以生效
<listener>
    <listener-class>com.socket.ServerListener</listener-class>
</listener>
  • 里面的ServerThread 是需要创建的第二个基本的类。
2、ServerThread
public class ServerThread extends Thread{

    private ServerSocket serverSocket = null;
    public static final int PORT = 8888;


    public ServerThread() {
        try{
            if(null == serverSocket){
                //1、创建一个服务端Socket,即ServerSocket,指定绑定的端口,并监听此端口
                this.serverSocket = new ServerSocket(PORT);
                System.out.println("=========服务端即将启动,监听客户端连接=========");
            }
        } catch (IOException e){
            System.out.println("创建服务端监听线程出错");
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        openServer();
    }

    public void openServer() {
        try {
            Socket socket = null;
            int count = 0;
            while (true) {
                System.out.println("正在监听第"+ (++count)+"次");
                //2、循环调用accept方法开始监听,等待客户端连接
                socket = serverSocket.accept();
                //创建一个新的线程
                ServerOperate serverThread = new ServerOperate(socket);
                //启动线程
                serverThread.start();

            }
            //因为循环监听,所以不会停止
            //serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void closeServer() {
        try {
            serverSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

解释:

  • 为什么第一步需要线程来创建ServerThread 呢?
    因为socket通信是通过accept()方法阻塞式监听的,而我们在创建ServerThread 类时,会执行到这个方法,这时候整个web程序就会阻塞而启动不了,所以我们需要另开启一个线程来执行这个阻塞式监听,所以这个类需要继承Thread,这样就不会影响web的主线程逻辑了。
  • 为什么要写在while循环里呢?
    因为我们不止监听一次,每次监听到数据传过来时,都会开启新线程处理数据,然后在回去继续监听。
  • 为什么要开启新线程处理数据呢?
    因为不可能在同一个线程上处理数据啊!
  • 里面的ServerOperate是需要创建的第三个基本的类
3、ServerOperate
public class ServerOperate extends Thread {
    //和本线程相关的socket
    Socket socket = null;

    public ServerOperate(Socket socket) {
        this.socket = socket;
    }

    //线程执行的操作,响应客户端的请求
    @Override
    public void run() {
        System.out.println("我要处理客户端发送的数据了");
        operate();
    }

    public void operate(){
        InputStream is = null;//字节流
        InputStreamReader isr = null;//转换为字符流
        BufferedReader br = null;//添加缓冲
        OutputStream os = null;
        PrintWriter pw = null;
        try {
            //3、获取输入流,读取客户端的信息
            is = socket.getInputStream();
            isr = new InputStreamReader(is,"utf-8");
            br = new BufferedReader(isr);
            String info = null;
            while ((info = br.readLine()) != null) {
                System.out.println("服务端接收到的客户端数据:" + info);
            }
            socket.shutdownInput();//关闭输入流
            //4、获取输出流,返回数据
            os = socket.getOutputStream();
            pw = new PrintWriter(os);
            pw.write("服务端欢迎您");
            pw.flush();//输出
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //5、关闭相关资源
                if (pw != null) pw.close();
                if (os != null) os.close();
                if (br != null) br.close();
                if (isr != null) isr.close();
                if (is != null) is.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

这三个类就基本写完了,没有写关闭的方法。

写main简单测一下

public static void main(String[] args) {
        try {
            //1、创建客户端socket,指定服务器地址端口
            Socket socket  = new Socket("localhost",8888);
            //2、获取输出流,发送数据
            OutputStream os = socket.getOutputStream();//字节输出流
            PrintWriter pw = new PrintWriter(os);//转换为打印流
            pw.write("我叫:Lisaqwe ");
            pw.flush();
            socket.shutdownOutput();//关闭输出流
            //3、获取输入流,读取响应信息
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is,"gbk"));
            String info =null;
            while((info=br.readLine())!=null){
                System.out.println("客户端接收响应的数据:"+info);
            }

            //4、关闭其他相关资源
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值