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通信的主要内容,如果未能解决你的问题,请参考以下文章

socket通信简介

Socket通信原理

Socket 通信之 UDP 通信

Socket通信 客户端(Android)

Socket通信 客户端(Android)

Socket通信 客户端(Android)