考完研闲来没事做,着手写一个TCP通信程序。也顺便复习了以下java中三种线程之间的区别与运用。
主要功能:能够实现TCP数据的接收与转发,并且可以通过同样的restful接口实现TCP中socket调用(通过唯一标识符deviceCode实现socket的绑定)
1、继承Thread类;
2、实现Runnable接口;(callback不做另外的解析)
大家在辨识Thread与Runnable很多还在extend与implement关键字之间的区别,Thread其实是实现了Runnable函数的,但是在具体的运用上,是由很大的区别。
通过继承Thread创建线程是不会阻塞主线程的后续执行的,尤其是在serverSocket.appect()方法的使用上,由于appect方法是阻塞的,所以在接收到连接的时候我们应该是使用继承thread的线程而非实现runable接口。
源码:https://github.com/AbitGo/mybatis_csdn/tree/master/TCPServer
首先来看实验现象
如果需要使用特定设备下发需要在发送之前绑定socket,就是第一次发送tcp数据格式需要进行数据绑定(下图即可
使用postman进行命令下发
以下为代码(基于Spring Boot的)
SocketParam.java
package com.bl.utli;
import com.bl.demo.subSocketClient;
import java.net.Socket;
import java.util.HashMap;
/**
* @author 韦海涛
* @version 1.0
* @date 2021/2/1 20:12
*/
public class SocketParam {
public static HashMap<String, subSocketClient> DeviceCode2SocketMap = new HashMap<>();
public static int PortNum = 7880;
public static String TypeRegister = "01";
public static String TypeUpdateData = "02";
public static String SendSuccess = "OK";
public static String SendError = "ERROR";
}
TCPServer.java
package com.bl.demo;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.*;
import static com.bl.utli.SocketParam.*;
public class TCPServer extends Thread {
ServerSocket serverSocket = null;
public static TCPServer tcpServer;
@PostConstruct
public void init(){
tcpServer = this;
tcpServer.start();
}
public String socketSendData(String deviceCode,String sendData){
//不为空时
subSocketClient temp = DeviceCode2SocketMap.get(deviceCode);
if(null!=temp){
return temp.sendSocketData(sendData,deviceCode);
}else{
return SendError;
}
}
@Override
public void run() {
try {
serverSocket = new ServerSocket(PortNum);
} catch (IOException e) {
System.out.println("the port cannot open.");
}
while(true){
try {
System.out.println("wait. .. ...");
//使用accept()是阻塞方法
Socket socketTemp = serverSocket.accept();
new subSocketClient(this.serverSocket,socketTemp).start();
//为每个连接都创建一个线程客户端
} catch (IOException e) {
System.out.println("happening");
}
}
}
}
subSocketClient.java
package com.bl.demo;
import com.alibaba.fastjson.JSONObject;
import javax.websocket.SendResult;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import static com.bl.utli.SocketParam.*;
/**
* @author 韦海涛
* @version 1.0
* @date 2021/2/1 20:53
*/
public class subSocketClient extends Thread {
private ServerSocket serverSocket;
private Socket socket;
public subSocketClient(ServerSocket serverSocket, Socket socket) {
this.serverSocket = serverSocket;
this.socket = socket;
}
public String sendSocketData(String sendData,String deviceCode){
try {
BufferedReader br = null;
PrintWriter pw = null;
br = new BufferedReader(new InputStreamReader(System.in));
pw = new PrintWriter(socket.getOutputStream(), true);
//查看socket是否存在
if (!socket.isClosed()) {
pw.println(sendData);
pw.flush();
return SendSuccess;
}else {
//不存在则移除该socket
DeviceCode2SocketMap.remove(deviceCode);
return SendError;
}
}catch (IOException e) {
e.printStackTrace();
}
return SendError;
}
@Override
public void run() {
try {
//获取输入流
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
byte[] buf = new byte[1024];
//接收数据
int line = 0;
while ((line = inputStream.read(buf)) != -1) {
String param = new String(buf, 0, line);
JSONObject jsonObject = JSONObject.parseObject(param);
String type = jsonObject.getString("type");
if(type.equals(TypeRegister)){
String deviceCode = jsonObject.getString("deviceCode");
DeviceCode2SocketMap.put(deviceCode,this);
//sendSocketData("OK",deviceCode);//测试
}
else if(type.equals(TypeUpdateData)){
String deviceCode = jsonObject.getString("deviceCode");
//这边方式存放数据
String deviceData = jsonObject.getString("deviceData");
}
}
//线程停止10ms
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}
控制.java
package com.bl.demo;
import com.alibaba.fastjson.JSONObject;
import com.bl.utli.PubicMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import static com.bl.demo.TCPServer.tcpServer;
import static com.bl.utli.SocketParam.SendError;
import static com.bl.utli.SocketParam.SendSuccess;
@RestController
public class TotolController {
@RequestMapping(value = "/Device/PostCommand", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@CrossOrigin
public String PostCommand(@RequestBody String GetJson) throws Exception {
JSONObject getJson = JSONObject.parseObject(GetJson);
String deviceCode = getJson.getString("deviceCode");
String sendData = getJson.getString("sendData");
String result = tcpServer.socketSendData(deviceCode,sendData);
if(result.equals(SendSuccess)){
return "下发成功";
}else if(result.equals(SendError)){
return "下发失败";
}
return "下发失败";
}
@RequestMapping(value = "/Device/Test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@CrossOrigin
public String Test() throws Exception {
return "OK";
}
}