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实现,更多...

SpringBoot之集成Socket的更多相关文章

  1. springboot elasticsearch 集成注意事项

    文章来源: http://www.cnblogs.com/guozp/p/8686904.html 一 elasticsearch基础 这里假设各位已经简单了解过elasticsearch,并不对es ...

  2. Springboot Application 集成 OSGI 框架开发

    内容来源:https://www.ibm.com/developerworks/cn/java/j-springboot-application-integrated-osgi-framework-d ...

  3. SpringBoot项目集成Hystrix

    Hystrix Hystrix是由Netflix开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟.异常,引起资源耗尽导致系统不可用的解决方案. 1.什么是服务熔断   服务熔断就是对该服务的调用 ...

  4. 钉钉通知机器人与SpringBoot的集成

    Spring Boot Admin 集成自定义监控告警(2.0.1版本)------钉钉机器人 - yuancao24的博客 - CSDN博客https://blog.csdn.net/yuancao ...

  5. SpringBoot项目集成PageHelper使用

    SpringBoot项目集成PageHelper使用 一.开始 ​ 地址:https://github.com/pagehelper/Mybatis-PageHelper ​ 在spring boot ...

  6. Springboot简单集成ActiveMQ

    Springboot简单集成ActiveMQ 消息发送者的实现 pom.xml添加依赖 <dependency> <groupId>org.springframework.bo ...

  7. 在springboot中集成mybatis开发

    在springboot中利用mybatis框架进行开发需要集成mybatis才能进行开发,那么如何在springboot中集成mybatis呢?按照以下几个步骤就可以实现springboot集成myb ...

  8. 在springboot中集成jsp开发

    springboot就是一个升级版的spring.它可以极大的简化xml配置文件,可以采用全注解形式开发,一个字就是很牛.在springboot想要使用jsp开发,需要集成jsp,在springboo ...

  9. Swagger详解(SpringBoot+Swagger集成)(转)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/ai_miracle/article/de ...

随机推荐

  1. python---修改编辑器的配色和字体大小

    因为习惯黑色的背景,所以必须修改成对应的配色: 在这里设置theme: 设置字体大小: 找到Font,这里设置字体大小,首先要Scheme 后 进行 Save as 操作后,才能设置 Size ,设置 ...

  2. PAT-GPLT L2-027 - 名人堂与代金券 - [简单模拟]

    题目链接:https://www.patest.cn/contests/gplt/L2-027 对于在中国大学MOOC(http://www.icourse163.org/)学习“数据结构”课程的学生 ...

  3. tkinter 进度条

    import tkinter as tk window = tk.Tk() window.title("我的窗口") window.geometry('600x400') var1 ...

  4. python面向对象高级:定制类

    Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类. 比如: __str__ 与__repr____iter____getitem____call__ __str__ 与__r ...

  5. 编译x11版本qt

    用buildroot 选择x11相关 在选择qt x11版本   export PATH=~/buildroot/output/host/usr/bin:$PATH 进入~/buildroot/out ...

  6. C# 多线程 详解

    [基础篇] 怎样创建一个线程 受托管的线程与Windows线程 前台线程与后台线程 名为BeginXXX和EndXXX的方法是做什么用的 异步和多线程有什么关联 [WinForm多线程编程篇] 多线程 ...

  7. Loadrunner之https协议录制回放报错如何解决?(九)

    一.录制中遇到报错27778的问题(如下图1),即关于录制的链接为https开头的问题,分两个步骤解决,如下: 图1 https访问报错解决步骤如下: 1.修改Vuser-->Run-time ...

  8. JS闭包中的循环绑定处理程序

    前几天工作中写前端js代码时,遇到了遍历元素给它添加单击事件.就是这个问题让我整整调了一个下午.最后还是下班回家,上网查资料才知道怎么解决的. (PS:之前也在<jQuery基础教程>第四 ...

  9. PAT Radix[二分][进制转换][难]

    1010 Radix (25)(25 分) Given a pair of positive integers, for example, 6 and 110, can this equation 6 ...

  10. PAT Product of Polynomials[一般]

    1009 Product of Polynomials (25)(25 分) This time, you are supposed to find A*B where A and B are two ...