多线程接收TCP Socket数据并用WebSocket发送

目录

一、线程池配置

二、代码主体

三、WebSocket配置

---------------------------------------------------------------------------------------------

一、线程池配置

直接上代码,我直接用的ruoyi系统里的线程池配置,个别依赖请自行查找导入

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * 线程相关工具类.
 *
 * 
 */
public class Threads
{
    private static final Logger logger = LoggerFactory.getLogger(Threads.class);

    /**
     * sleep等待,单位为毫秒
     */
    public static void sleep(long milliseconds)
    {
        try
        {
            Thread.sleep(milliseconds);
        }
        catch (InterruptedException e)
        {
            return;
        }
    }

    /**
     * 停止线程池
     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
     * 如果仍然超時,則強制退出.
     * 另对在shutdown时线程本身被调用中断做了处理.
     */
    public static void shutdownAndAwaitTermination(ExecutorService pool)
    {
        if (pool != null && !pool.isShutdown())
        {
            pool.shutdown();
            try
            {
                if (!pool.awaitTermination(120, TimeUnit.SECONDS))
                {
                    pool.shutdownNow();
                    if (!pool.awaitTermination(120, TimeUnit.SECONDS))
                    {
                        logger.info("Pool did not terminate");
                    }
                }
            }
            catch (InterruptedException ie)
            {
                pool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 打印线程异常信息
     */
    public static void printException(Runnable r, Throwable t)
    {
        if (t == null && r instanceof Future<?>)
        {
            try
            {
                Future<?> future = (Future<?>) r;
                if (future.isDone())
                {
                    future.get();
                }
            }
            catch (CancellationException ce)
            {
                t = ce;
            }
            catch (ExecutionException ee)
            {
                t = ee.getCause();
            }
            catch (InterruptedException ie)
            {
                Thread.currentThread().interrupt();
            }
        }
        if (t != null)
        {
            logger.error(t.getMessage(), t);
        }
    }
}
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 *
 * 
 **/
@Configuration
public class ThreadPoolConfig
{
    // 核心线程池大小
    private int corePoolSize = 50;

    // 最大可创建的线程数
    private int maxPoolSize = 200;

    // 队列最大长度
    private int queueCapacity = 1000;

    // 线程池维护线程所允许的空闲时间
    private int keepAliveSeconds = 300;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService()
    {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy())
        {
            @Override
            protected void afterExecute(Runnable r, Throwable t)
            {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }
}

二、代码主体

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.*;


@Component
public class SocketServer implements CommandLineRunner {
   
    private Integer port = 监听的端口;

    @Autowired
    private WebSocket webSocket;
 
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

//程序启动自动执行
    @Override
    public void run(String... args) throws Exception {
        ServerSocket ss = null;
        try {
            ss = new ServerSocket(port);

            while (true) {//持续监听端口
                Socket accept = ss.accept();
                //socket连接交由线程池管理
                threadPoolTaskExecutor.execute(new ClientHandler(accept));
            }
        } catch (IOException e0) {
            e0.printStackTrace();
        } finally {
            if (ss != null) {
                try {
                    ss.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
// 客户端处理类,实现Runnable接口
    private class ClientHandler implements Runnable {
        private final Socket accept;

        ClientHandler(Socket accept) {
            this.accept = accept;
        }

		//分配线程后执行的方法
        @Override
        public void run() {
			
			InputStream inputStream = null;
			try {
				inputStream = accept.getInputStream();
			} catch (IOException e) {
                e.printStackTrace();
			}
			BufferedInputStream bis = new BufferedInputStream(inputStream);
			//处理bis流部分
			根据需求处理流
				
			//发送websocket(注意发送代码的位置,如果一次连接发送数据持续时间较久可能需要放到处理流的过程中)
			webSocket.sendAllMessage(发送内容);

			System.out.println("读取结束");
			//关闭
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
            if (accept != null) {
                try {
                    accept.close();
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

三、WebSocket配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    /**
     * 注入ServerEndpointExporter,
     * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/websocket/{clientId}")
//此注解相当于设置访问URL
public class WebSocket {
    private static final Logger log = LoggerFactory.getLogger(WebSocket.class);
    private Session session;
    private String clientId;
    private static Map<String,WebSocket> webSockets = new ConcurrentHashMap<>();
    private static int onlineCount = 0;

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "clientId") String clientId) {
        this.session = session;
        this.clientId = clientId;
        webSockets.put(clientId,this);
        onlineCount++;
        log.info(clientId+"【websocket消息】有新的连接,总数为:"+onlineCount);
    }

    @OnClose
    public void onClose() {
        webSockets.remove(clientId);
        onlineCount--;
        log.info("【websocket消息】连接断开,总数为:"+onlineCount);
    }

    @OnMessage
    public void onMessage(String message,Session session) throws IOException {
        if (session != null) {
            this.session.getAsyncRemote().sendText(message);
            log.info("【websocket消息】客户端发来消息:"+message);
        }
    }
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("WebSocket发生错误:" + throwable.getMessage());
    }

    // 此为广播消息,synchronized 防止多线程同时使用同一个session进行写操作
    public synchronized void sendAllMessage(String message) {
        for (WebSocket item : webSockets.values()) {
            if (item.session.isOpen()) {
                try {
                    item.session.getAsyncRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        log.info("【websocket消息】广播消息:" + message);
    }

    // 此为单点消息(目前不能用,不知道为什么clientId获取不到,用之前可以先试一下是否可行)
    public Boolean sendOneMessage(String message) {

        WebSocket webSocket = webSockets.get(clientId);
        if (session != null) {
            try {
                if (session.isOpen()) {
                    System.out.println("【websocket消息】单点消息:"+message);
                    webSocket.session.getAsyncRemote().sendText(message);
                    return true;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}

sendAllMessage实现广播发送给每一个客户端,具体发送需求可以自己调整

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
编写多线程多设备通讯需要考虑以下几个方面: 1. 设备通讯协议:首先需要确定设备之间通讯采用何种协议,例如TCP/IP、UDP、HTTP、WebSocket等。 2. 网络连接:每个设备需要建立网络连接,可以使用socket库来实现。 3. 多线程:为了实现多线程通讯,可以使用Python的threading模块,每个线程负责与一个设备进行通讯。 4. 数据传输:数据需要在设备之间进行传输,可以使用Python的socket库提供的send和recv方法进行数据传输。 下面是一个简单的示例代码,实现了两个设备之间的通讯: ```python import threading import socket def device_1(): # 建立socket连接 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('192.168.0.2', 8888)) while True: # 接收device_2发送数据 data = s.recv(1024) if not data: break # 处理数据 print('device_1 received:', data) s.close() def device_2(): # 建立socket连接 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('192.168.0.2', 8888)) s.listen(1) conn, addr = s.accept() while True: # 发送数据给device_1 data = input('device_2 input:') conn.send(data.encode()) conn.close() if __name__ == '__main__': # 创建两个线程,分别负责device_1和device_2的通讯 t1 = threading.Thread(target=device_1) t2 = threading.Thread(target=device_2) # 启动线程 t1.start() t2.start() # 等待线程结束 t1.join() t2.join() ``` 这个示例代码中,device_1和device_2分别表示两个设备。device_1通过socket连接到device_2,然后循环接收device_2发送数据并进行处理;device_2先绑定socket,然后等待device_1连接,接收device_1发送数据并进行处理。两个设备之间的数据传输采用TCP协议,即建立连接后进行可靠的数据传输。多线程由Python的threading模块实现,两个线程分别负责device_1和device_2的通讯。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值