Socket通信

Posted singulariity-gs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Socket通信相关的知识,希望对你有一定的参考价值。

本次分享的是一个简单的Web项目里使用的Socket通信案例

1、建立监听类:

package com.trust.fricem.TCPC.service;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
 * @Author:Singularity
 * @Date:2019/6/1 14:23
 * @Description: Socket 服务监听
 */
public class SocketServiceLoader implements ServletContextListener 

    //socket server 线程
    private SocketThread socketThread;

    /**
     * 当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,
     * 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
     */
    @Override
    public void contextInitialized(final ServletContextEvent sce) 
        System.out.println("容器启动-------");
        if (null == socketThread) 
            //新建线程类
            WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
            socketThread = new SocketThread(null, wac);
            //启动线程
            socketThread.start();
        
    

    /**
     * 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。
     */
    @Override
    public void contextDestroyed(ServletContextEvent sce) 
        System.out.println("容器终止-------");
        if (null != socketThread && !socketThread.isInterrupted()) 
            socketThread.closeSocketServer();
            socketThread.interrupt();
        
    

2、创建线程类,同时创建 ServerSocket 服务端并监听客户端的连接

package com.trust.fricem.TCPC.service;

import com.trust.fricem.TCPC.controller.SocketDataDealController;
import org.springframework.web.context.WebApplicationContext;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author:Singularity
 * @Date:2019/6/1 14:32
 * @Description: Socket 服务端
 */
public class SocketThread extends Thread 
    private ExecutorService threadPool = Executors.newFixedThreadPool(100);
    private ServerSocket serverSocket = null;
    private WebApplicationContext webApplicationContext = null;
    Socket socket;
    BufferedReader reader;
    BufferedWriter writer;

    public SocketThread(ServerSocket serverScoket, WebApplicationContext wac) 
        try 
            if (null == serverSocket) 
                this.serverSocket = new ServerSocket(8088);
                webApplicationContext = wac;
                System.out.println("socket start");
                System.out.println("Spring 容器 webApplicationContext 获取");
            
         catch (Exception e) 
            System.out.println("SocketThread创建socket服务出错");
            e.printStackTrace();
        

    

    public void run() 
        while (!this.isInterrupted()) 
            try 
                //1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 1024-65535的某个端口
                while (true) // 巧用死循环
                    //2、调用accept()方法开始监听,等待客户端的连接
                    socket = serverSocket.accept();

                    InetAddress address = socket.getInetAddress();//获取远程客户端的IP信息
                    System.out.println("InetAddress:" + address);
                    System.out.println("IP地址:" + address.getHostAddress());
                    System.out.println("主机名:" + address.getHostName());

                    reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//读取客户端消息
                    writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//向客户端写消息
                    try 
                        //3、获取输入流,并读取客户端信息
                        String info = null;
                        SocketDataDealController sdd = new SocketDataDealController(webApplicationContext);
                        while (!(info = reader.readLine()).equals("bye")) 
                            System.out.println("收到来自客户端的发送的消息是:" + new String(info.getBytes(), "UTF-8"));
                            String returnInfo = sdd.dealSocketData(info);
                            System.out.println("给客户端的发送的消息是:" + returnInfo);
                            writer.write(new String(returnInfo.getBytes(), "UTF-8") + "\n");
                            writer.flush();
                        
                     catch (IOException e) 
                        e.printStackTrace();
                     finally 
                        try 
                            if (reader != null) 
                                reader.close();
                            
                            if (writer != null) 
                                writer.close();
                            
                            if (socket != null) 
                                System.out.println("Socket通道关闭");
                                socket.close();
                            
                         catch (Exception e2) 
                            e2.printStackTrace();
                        
                    
                
             catch (Exception e) 
                e.printStackTrace();
            
        
    

    public void closeSocketServer() 
        try 
            if (null != serverSocket && !serverSocket.isClosed()) 
                System.out.println("ServerSocket 终止");
                serverSocket.close();
            
         catch (IOException e) 
            e.printStackTrace();
        
    

3、处理客户端数据类,其中包含调用 Service 层方法的用法

package com.trust.fricem.QRCode.controller;

import com.trust.fricem.QRCode.entity.ProdQRCodeEntity;
import com.trust.fricem.QRCode.entity.ReturnMessage;
import com.trust.fricem.QRCode.entity.UniversalcodeEntity;
import com.trust.fricem.QRCode.service.ProdQRCodeService;
import com.trust.fricem.QRCode.service.UniversaleCodeService;
import com.trust.fricem.common.Constant;
import com.trust.fricem.common.util.ASCIIUtils;
import com.trust.fricem.common.util.CRC8;
import com.trust.fricem.equipment.entity.EquipmenttypeEntity;
import com.trust.fricem.equipment.service.EquipmenttypeDisService;
import com.trust.fricem.product.entity.ProducttypeEntity;
import com.trust.fricem.product.service.ProductTypeService;
import org.springframework.web.context.WebApplicationContext;

/**
 * GPRS 通信接口
 * @author Singularity
 * @Time 2019.2.25
 */
public class SCMInterface 

    private WebApplicationContext context = null;
    private ProdQRCodeService prodQRCodeService;
    private EquipmenttypeDisService equipmenttypeDisService;
    private ProductTypeService productTypeService;
    private UniversaleCodeService universaleCodeService;

    public SCMInterface(WebApplicationContext webApplicationContext) 
        context = webApplicationContext;
        // 利用 webApplicationContext 创建 service 
        prodQRCodeService = context.getBean(ProdQRCodeService.class);
        equipmenttypeDisService = context.getBean(EquipmenttypeDisService.class);
        productTypeService = context.getBean(ProductTypeService.class);
        universaleCodeService = context.getBean(UniversaleCodeService.class);

    


    /**
     * 接口1
     */
    public String receiveMessage(String param) 
        ReturnMessage object = null;
        String returnStr = null;
        if (null != object) 
            if (null != object.getCodeStr()) 
                String str = object.getCodeStr();
                if (null != str && "" != str) 
                    //二维码类型标识
                    String codeType = str.substring(0, 2);
                    if (Constant.PROQrCode_BS.equals(codeType)) //----普通二维码
                        returnStr = prodQRCodeService.updateQrCodeInfo(object);//修改二维码加工状态
                    
                    if (Constant.PROQrCode_WS.equals(codeType)) //----万能二维码
                        returnStr = universaleCodeService.saveUniversaleCode(object);//添加万能码使用记录数据
                        //returnStr = CRC8.returnType(Constant.PROQrCode_SUCCESS, Constant.PROQrCode_EQUIPNO);
                    
                
            
        
        return returnStr;
    

4、再 Web.xml 中添加监听

<!-- spring监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 防止spring内存溢出监听器,比如quartz -->
    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>

    <!-- Socket 监听器 (注意,监听要放在 Spring 之后,不然创建的 ServletContextEvent 是空的)-->
    <listener>
        <listener-class>com.trust.fricem.TCPC.service.SocketServiceLoader</listener-class>
    </listener>

注意:由于使用的是 Servlet 的监听方法,servlet 容器是在 Spring 容器之前加载的,而本次我用的是 SSM 框架,其中的 service 层和 dao 层等使用 Spring 容器管理的,所以上方的黄色标注的地方调用的方法会报错, 其中的 webApplicationContext 就是为了解决,这个问题 (有什么不对或者不合理的地方,欢迎大家赐教!)

以上是关于Socket通信的主要内容,如果未能解决你的问题,请参考以下文章