• SpringBoot之集成Socket


     
    1、Socket是什么,这里不做介绍。开发环境:jdk1.8,win7_64旗舰版,idea
     
    2、初始化一个springboot项目
     
    3、开始Socket服务端实现,Socket相关接口在java.net包中已经存在,所以这里不需要再做额外的引用
        3.1、SocketServer,是Socket服务端核心
    package com.geniuses.sewage_zero_straight.net.socket;
    
    import com.geniuses.sewage_zero_straight.bean.User;
    import com.geniuses.sewage_zero_straight.service.UserService;
    import com.geniuses.sewage_zero_straight.util.JSONUtil;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import static com.geniuses.sewage_zero_straight.net.socket.SocketHandler.*;
    
    @Slf4j
    @Data
    @Component
    @PropertySource("classpath:socket.properties")
    @NoArgsConstructor
    public class SocketServer {
    
        @Value("${port}")
        private Integer port;
        private boolean started;
        private ServerSocket serverSocket;
        private ExecutorService executorService = Executors.newCachedThreadPool();
    
        public static void main(String[] args){
            new SocketServer().start(8068);
        }
    
        public void start(){
            start(null);
        }
        @Autowired
        private UserService userService;//测试使用
    
    
        public void start(Integer port){
            log.info("port: {}, {}", this.port, port);
            try {
                serverSocket =  new ServerSocket(port == null ? this.port : port);
                started = true;
                log.info("Socket服务已启动,占用端口: {}", serverSocket.getLocalPort());
            } catch (IOException e) {
                log.error("端口冲突,异常信息:{}", e);
                System.exit(0);
            }
    
            while (started){
                try {
                    Socket socket = serverSocket.accept();
                    socket.setKeepAlive(true);
                    ClientSocket register = register(socket);
                    log.info("客户端已连接,其Key值为:{}", register.getKey());
                    List<User> list = userService.queryEntityListAll();
                    SocketHandler.sendMessage(register, JSONUtil.toJson(list));
                    if (register != null){
                        executorService.submit(register);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

        3.2、SocketPool是Socket连接的池,存放着所有已连接的socket对象,ClientSocket是自定义的一个客户端Socket类

    package com.geniuses.sewage_zero_straight.net.socket;
    
    import java.util.concurrent.ConcurrentHashMap;
    
    public class SocketPool {
    
        private static final ConcurrentHashMap<String, ClientSocket> ONLINE_SOCKET_MAP = new ConcurrentHashMap<>();
    
    
        public static void add(ClientSocket clientSocket){
            if (clientSocket != null && !clientSocket.getKey().isEmpty())
                ONLINE_SOCKET_MAP.put(clientSocket.getKey(), clientSocket);
        }
    
        public static void remove(String key){
            if (!key.isEmpty())
                ONLINE_SOCKET_MAP.remove(key);
        }
    }

        3.3、ClientSocket

    package com.geniuses.sewage_zero_straight.net.socket;
    
    import com.geniuses.sewage_zero_straight.bean.LZP_DATASERVER_TC_PROHIBSOURCE;
    import com.geniuses.sewage_zero_straight.service.LZP_DATASERVER_TC_PROHIBSOURCEService;
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.net.Socket;
    import java.util.concurrent.TimeUnit;
    
    import static com.geniuses.sewage_zero_straight.net.socket.SocketHandler.*;
    
    /**
     * @author zhoujian
     * 自定义封装的连接的客户端
     */
    @Slf4j
    @Data
    public class ClientSocket implements Runnable{
    
        private Socket socket;
        private DataInputStream inputStream;
        private DataOutputStream outputStream;
        private String key;
        private String message;
    
        @Override
        public void run() {
            //每5秒进行一次客户端连接,判断是否需要释放资源
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(5);
    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (isSocketClosed(this)){
                    log.info("客户端已关闭,其Key值为:{}", this.getKey());
                    //关闭对应的服务端资源
                    close(this);
                    break;
                }
            }
        }
    }

    3.4、SocketHandler,Socket操作处理类

    package com.geniuses.sewage_zero_straight.net.socket;
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.Socket;
    
    import static com.geniuses.sewage_zero_straight.net.socket.SocketPool.*;
    
    /**
     * Socket操作处理类
     */
    @Slf4j
    public class SocketHandler{
    
    
        /**
         * 将连接的Socket注册到Socket池中
         * @param socket
         * @return
         */
        public static ClientSocket register(Socket socket){
            ClientSocket clientSocket = new ClientSocket();
            clientSocket.setSocket(socket);
            try {
                clientSocket.setInputStream(new DataInputStream(socket.getInputStream()));
                clientSocket.setOutputStream(new DataOutputStream(socket.getOutputStream()));
                byte[] bytes = new byte[1024];
                clientSocket.getInputStream().read(bytes);
                clientSocket.setKey(new String(bytes, "utf-8"));
                add(clientSocket);
                return clientSocket;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 向指定客户端发送信息
         * @param clientSocket
         * @param message
         */
        public static void sendMessage(ClientSocket clientSocket, String message){
            try {
                clientSocket.getOutputStream().write(message.getBytes("utf-8"));
                //clientSocket.getOutputStream().writeUTF(message);
            } catch (IOException e) {
                log.error("发送信息异常:{}", e);
                close(clientSocket);
            }
        }
    
        /**
         * 获取指定客户端的上传信息
         * @param clientSocket
         * @return
         */
        public static String onMessage(ClientSocket clientSocket){
            byte[] bytes = new byte[1024];
            try {
                clientSocket.getInputStream().read(bytes);
                String msg = new String(bytes, "utf-8");
                return msg;
            } catch (IOException e) {
                e.printStackTrace();
                close(clientSocket);
            }
            return null;
        }
    
        /**
         * 指定Socket资源回收
         * @param clientSocket
         */
        public static void close(ClientSocket clientSocket){
            log.info("进行资源回收");
            if (clientSocket != null){
                log.info("开始回收socket相关资源,其Key为{}", clientSocket.getKey());
                remove(clientSocket.getKey());
                Socket socket = clientSocket.getSocket();
                try {
                    socket.shutdownInput();
                    socket.shutdownOutput();
                } catch (IOException e) {
                    log.error("关闭输入输出流异常,{}", e);
                }finally {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        log.error("关闭socket异常{}", e);
                    }
                }
            }
        }
    
    
        /**
         * 发送数据包,判断数据连接状态
         * @param clientSocket
         * @return
         */
        public static boolean isSocketClosed(ClientSocket clientSocket){
            try {
                clientSocket.getSocket().sendUrgentData(1);
                return false;
            } catch (IOException e) {
                return true;
            }
        }
    
    }

    4、模拟客户端

    package com.geniuses.sewage_zero_straight.net.socket;
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.io.*;
    import java.net.Socket;
    import java.util.UUID;
    
    @Slf4j
    public class ChatClient {
    
        public static void main(String[] args) throws IOException {
            String host = "192.168.2.156";
            int port = 8068;
    
            //与服务端建立连接
            Socket socket = new Socket(host, port);
            socket.setOOBInline(true);
    
            //建立连接后获取输出流
            DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
            DataInputStream inputStream = new DataInputStream(socket.getInputStream());
            String uuid = UUID.randomUUID().toString();
            log.info("uuid: {}", uuid);
            outputStream.write(uuid.getBytes());
            DataInputStream inputStream1 = new DataInputStream(socket.getInputStream());
            String content = "";
            while (true){
                byte[] buff = new byte[1024];
                inputStream.read(buff);
                String buffer = new String(buff, "utf-8");
                content += buffer;
                log.info("info: {}", buff);
                File file = new File("json.json");
                FileWriter fileWriter = new FileWriter(file);
                fileWriter.write(content);
                fileWriter.flush();
            }
        }
    }

    5、Socket配置,这样,在启动SpringBoot应用的时候,就会将Socket服务也一并启动(此处有坑,也就是启动方式的问题,使用内置的tomcat启动是可以这样操作的,如果打包为war包在外置的tomcat进行启动,那么这里的设置是无效的,如何操作:)

    package com.geniuses.sewage_zero_straight;
    
    import com.geniuses.sewage_zero_straight.net.socket.SocketServer;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ApplicationContext;
    
    @SpringBootApplication
    public class SocketApplication{
    
        public static void main(String[] args) {
            ApplicationContext applicationContext = SpringApplication.run(SocketApplication.class, args);
            applicationContext.getBean(SocketServer.class).start();//在spring容器启动后,取到已经初始化的SocketServer,启动Socket服务
        }
    
    }

    6、这里只是简单的Socket实现,更多...

  • 相关阅读:
    HMM 学习一
    matlab buffer的使用
    JDK环境变量配置及Tomcat安装服务
    Js参数RSA加密传输,jsencrypt.js的使用
    Dapper基本增删改查
    Dapper事务操作
    Ubuntu知识记录
    InstallShield 覆盖安装
    Limited Edition for Visual Studio 2013 图文教程(教你如何打包.NET程序)
    Sql Server导出表结构Excel
  • 原文地址:https://www.cnblogs.com/threadj/p/10553048.html
Copyright © 2020-2023  润新知