目前要做人机交互界面的后台,人机对话内容需要实时展示在机器人屏幕上,人机对话的内容由语音系统推送到后台,用的是tcp协议,tcp的服务端我不用管,现在我需要把语音系统推给我的内容给到前端;由于语音系统底层才用的是C和C++;不方便用websocket,不然前端可以直接用websocket接收语音系统的数据。
实现想法:后台用socket来接收语音系统的数据,再搭建一个websocket服务端把接受到的数据推送给前端
socket客户端:ClientTestCommunicate
@Component
public class ClientTestCommunicate extends Thread {
// public static void main(String[] args) {
public static void start(String[] args) {
try {
//Socket client = new Socket("192.168.5.8", 17080);
Socket client = new Socket("127.0.0.1", 1234);
// client.setSoTimeout(20000);//设置socket连接时间
System.out.println("当前是客户端窗口:");
new CReceiveMsgThread(client).start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start() {
start(null);
}
}
// 接收消息线程
class CReceiveMsgThread extends Thread {
// 这里使用静态,让 service 属于类
/*private static WebSocketProcess webSocketProcess;
@Autowired
public void setWebSocketProcess(WebSocketProcess webSocketProcess) {
CReceiveMsgThread.webSocketProcess = webSocketProcess;
}
*/
Socket client;
public CReceiveMsgThread(Socket client) {
this.client = client;
}
@Override
public void run() {
// new SendMsgThread(client).start();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
String str;
while (!client.isClosed()&&(str = reader.readLine()) != null) {
System.out.println("msg from server:" + str);
SpringContextUtil.getBean(WebSocketProcess.class).sendAllMessage(str);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 发送消息线程
class CSendMsgThread extends Thread {
Socket response;
public CSendMsgThread(Socket response) {
this.response = response;
}
@Override
public void run() {
try {
BufferedReader keyboardReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
String tempStr = "";
while (!tempStr.contains("bye")) {
tempStr = keyboardReader.readLine();
// tempStr=URLEncoder.encode(tempStr, "UTF-8");//加码
writer.write(tempStr + "\n");
writer.flush();
}
System.out.println("结束会话!");
keyboardReader.close();
writer.close();
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户端通过@Autowired注入的webSocketProcess为null,原因和解决方法在另一篇文章 点击这里 有写,这里我用SpringContextUtil这个工具类来获得webSocketProcess对象,工具类代码也会放在那里
socket服务端, 这里通过控制台输入,模拟socket服务端发消息,但到时候只需要客户端就可以:
@Component
public class ServerTestCommunicate {
private static final int PORT = 1234;
//public static void main(String[] args) {
public static void start(String[] args) {
try {
ServerSocket server = new ServerSocket(PORT);
new ReceiveMsgThread(server).start();// 开启消息接收
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start() {
start(null);
}
}
// 处理接收消息的线程
class ReceiveMsgThread extends Thread {
ServerSocket server;
public ReceiveMsgThread(ServerSocket server) {
this.server = server;
}
@Override
public void run() {
try {
System.out.println("当前是服务器127.0.0.1窗口:");
Socket response = server.accept();
System.out.println("已有客户端连接:" + response.getInetAddress().getHostAddress());
new SendMsgThread(response).start();// 连接上,开启发送线程
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getInputStream()));
String str;
while ((str = reader.readLine()) != null) {
// str=URLDecoder.decode(str, "UTF-8");//解码
System.out.println("msg from client:" + str);
}
//关闭
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 处理发送消息线程
class SendMsgThread extends Thread {
Socket response;
public SendMsgThread(Socket response) {
this.response = response;
}
@Override
public void run() {
try {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
BufferedReader keyboardReader = new BufferedReader(new InputStreamReader(System.in));
// InputStreamReader in=new InputStreamReader(System.in, "UTF-8");
String tempStr = "";
while ((tempStr = keyboardReader.readLine()) != null) {
// tempStr=URLEncoder.encode(tempStr, "UTF-8");//加码
writer.write(tempStr + "\n");
writer.flush();
}
System.out.println("结束会话!");
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
主启动类里面让socket、服务端、客户端随项目运行
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class AppclientApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppclientApplication.class, args);
context.getBean(ServerTestCommunicate.class).start();
context.getBean(ClientTestCommunicate.class).start();
}
}
websocket服务端:
@Slf4j
@Component
@ServerEndpoint(value = "/testWebSocket/{id}")
public class WebSocketProcess {
/*
* 持有每个webSocket对象,以key-value存储到线程安全ConcurrentHashMap,
*/
private static ConcurrentHashMap<Long, WebSocketProcess> concurrentHashMap = new ConcurrentHashMap<>(12);
/*private static WebSocketProcess webSocketProcess;
@Autowired
public void setWebSocketProcess(WebSocketProcess webSocketProcess) {
WebSocketProcess.webSocketProcess = webSocketProcess;
}*/
/**
* 会话对象
**/
private Session session;
/*
* 客户端创建连接时触发
* */
@OnOpen
public void onOpen(Session session, @PathParam("id") long id) {
//每新建立一个连接,就把当前客户id为key,this为value存储到map中
this.session = session;
concurrentHashMap.put(id, this);
log.info("Open a websocket. id={}", id);
}
/**
* 客户端连接关闭时触发
**/
@OnClose
public void onClose(Session session, @PathParam("id") long id) {
//客户端连接关闭时,移除map中存储的键值对
concurrentHashMap.remove(id);
log.info("close a websocket, concurrentHashMap remove sessionId= {}", id);
}
/**
* 接收到客户端消息时触发
*/
@OnMessage
public void onMessage(String message, @PathParam("id") String id) {
log.info("receive a message from client id={},msg={}", id, message);
}
/**
* 连接发生异常时候触发
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("Error while websocket. ", error);
}
/**
* 发送消息到指定客户端
* @param id
* @param message
* */
public void sendMessage(long id, String message) throws Exception {
//根据id,从map中获取存储的webSocket对象
WebSocketProcess webSocketProcess = concurrentHashMap.get(id);
if (!ObjectUtils.isEmpty(webSocketProcess)) {
//当客户端是Open状态时,才能发送消息
if (webSocketProcess.session.isOpen()) {
webSocketProcess.session.getBasicRemote().sendText(message);
} else {
log.error("websocket session={} is closed ", id);
}
} else {
log.error("websocket session={} is not exit ", id);
}
}
/**
* 发送消息到所有客户端
*
* */
public void sendAllMessage(String msg) throws Exception {
log.info("online client count={}", concurrentHashMap.size());
Set<Map.Entry<Long, WebSocketProcess>> entries = concurrentHashMap.entrySet();
for (Map.Entry<Long, WebSocketProcess> entry : entries) {
Long cid = entry.getKey();
WebSocketProcess webSocketProcess = entry.getValue();
boolean sessionOpen = webSocketProcess.session.isOpen();
if (sessionOpen) {
// webSocketProcess.session.getBasicRemote().sendText(msg);
webSocketProcess.session.getBasicRemote().sendText(msg);
} else {
log.info("cid={} is closed,ignore send text", cid);
}
}
}
}
控制台模拟的socket服务端,输入,成功在前台输入框展示。