最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Springboot之整合Socket连接代码示例
时间:2021-01-29 编辑:袖梨 来源:一聚教程网
本篇文章小编给大家分享一下Springboot之整合Socket连接代码示例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。
Socket连接与硬件通信
一、如何让socket随着springboot项目一起启动
SpringBoot中CommandLineRunner的作用:平常开发中有可能需要实现在项目启动后执行的功能,SpringBoot提供的一种简单的实现方案就是添加一个model并实现CommandLineRunner接口,实现功能的代码放在实现的run方法中
具体实现
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @author 易水●墨龙吟 * @Description * @create 2019-04-14 23:40 */ @Component public class TestRunner implements CommandLineRunner { @Autowired private SocketProperties properties; @Override public void run(String... args) throws Exception { ServerSocket server = null; Socket socket = null; server = new ServerSocket(properties.getPort()); System.out.println("设备服务器已经开启, 监听端口:" + properties.getPort()); ThreadPoolExecutor pool = new ThreadPoolExecutor( properties.getPoolCore(), properties.getPoolMax(), properties.getPoolKeep(), TimeUnit.SECONDS, new ArrayBlockingQueue(properties.getPoolQueueInit()), new ThreadPoolExecutor.DiscardOldestPolicy() ); while (true) { socket = server.accept(); pool.execute(new ServerConfig(socket)); } } }
此处使用了自定义的线程池,提高对于socket的客户端处理能力。
二、自定义配置并使用
此处将socket的端口和线程池的一些配置放到 application.yml中使用,方便使用和修改
# Socket配置 socket: # 监听端口 2323 port: 2323 # 线程池 - 保持线程数 20 pool-keep: 20 # 线程池 - 核心线程数 10 pool-core: 10 # 线程池 - 最大线程数 20 pool-max: 30 # 线程队列容量 10 pool-queue-init: 10
import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; /** * @author 易水●墨龙吟 * @Description * @create 2019-04-18 22:35 */ @Setter @Getter @ToString @Component @Configuration @PropertySource("classpath:application.yml") @ConfigurationProperties(prefix = "socket") public class SocketProperties { private Integer port; private Integer poolKeep; private Integer poolCore; private Integer poolMax; private Integer poolQueueInit; }
三、Socket对于客户端发来的信息的处理和重发机制
当客户端端连接之后发送信息,如果超时未发送,将会关闭,发送数据有异常将会返回给客户端一个error,让客户端在发送一次数据。
import com.farm.config.socket.resolve.MessageChain; import com.farm.service.EnvironmentService; import com.farm.service.impl.EnvironmentServiceImpl; import java.io.*; import java.net.Socket; import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.Map; /** * @author 易水●墨龙吟 * @Description * @create 2019-04-14 23:21 */ public class ServerConfig extends Thread { private Socket socket; public ServerConfig(Socket socket) { this.socket = socket; } // 获取spring容器管理的类,可以获取到sevrice的类 private EnvironmentService service = SpringUtil.getBean(EnvironmentServiceImpl.class); private String handle(InputStream inputStream) throws IOException, DataFormException { byte[] bytes = new byte[1024]; int len = inputStream.read(bytes); if (len != -1) { StringBuffer request = new StringBuffer(); request.append(new String(bytes, 0, len, "UTF-8")); System.out.println("接受的数据: " + request); System.out.println("from client ... " + request + "当前线程" + Thread.currentThread().getName()); Mapmap = MessageChain.out(request.toString()); System.out.println("处理的数据" + map); Integer res = service.addEnvironment(map); if (res == 1) { return "ok"; } else { throw new DataFormException("数据处理异常"); } } else { throw new DataFormException("数据处理异常"); } } @Override public void run() { BufferedWriter writer = null; try { // 设置连接超时9秒 socket.setSoTimeout(9000); System.out.println("客户 - " + socket.getRemoteSocketAddress() + " -> 机连接成功"); InputStream inputStream = socket.getInputStream(); writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String result = null; try { result = handle(inputStream); writer.write(result); writer.newLine(); writer.flush(); } catch (IOException | DataFormException | IllegalArgumentException e) { writer.write("error"); writer.newLine(); writer.flush(); System.out.println("发生异常"); try { System.out.println("再次接受!"); result = handle(inputStream); writer.write(result); writer.newLine(); writer.flush(); } catch (DataFormException | SocketTimeoutException ex) { System.out.println("再次接受, 发生异常,连接关闭"); } } } catch (SocketException socketException) { socketException.printStackTrace(); try { writer.close(); } catch (IOException ioException) { ioException.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } finally { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } }
在此处有一个坑,如果客户端是用C/C++编写的,必须使用如下方法:
byte[] bytes = new byte[1024]; int len = inputStream.read(bytes);
如果使用readLine或者 DataInputStream dataInputStream =new DataInputStream(socket.getInputStream())这样会出现使用TCP连接助手,客户端发送数据收不到。
四、如何在普通类中使用Spring注入类
这里需要使用一个工具类。
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @author 易水●墨龙吟 * @Description * @create 2019-04-15 0:01 */ @Component public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (SpringUtil.applicationContext == null) { SpringUtil.applicationContext = applicationContext; } } /** * 获取applicationContext * @return */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 通过name获取 Bean. * @param name * @return */ public static Object getBean(String name){ return getApplicationContext().getBean(name); } /** * 通过class获取Bean. * @param clazz * @param* @return */ public static T getBean(Class clazz){ return getApplicationContext().getBean(clazz); } /** * 通过name,以及Clazz返回指定的Bean * @param name * @param clazz * @param * @return */ public static T getBean(String name,Class clazz){ return getApplicationContext().getBean(name, clazz); } }
相关文章
- SpringBoot自定义bean绑定解析 10-24
- Javaweb工程运行报错HTTP Status 404解决教程 10-20
- JAVA获取jvm和操作系统相关信息方法 10-20
- BeanFactory和FactoryBean的区别讲解 10-20
- 微信小程序的宿主环境实现教程 10-10
- dispatchEvent解决重叠元素响应事件教程 10-10