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實現,更多...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM