,我在下面設置一個簡單的socket服務器編寫代碼,我感到困惑添加下面期貨到我的socket服務器:春天TCP套接字,授權客戶和處理Spring框架支持TCP連接以及未決響應
-
基於唯一的標識符
- 授權客戶端(例如,從客戶端接收的客戶端密鑰,也許使用TCP Connection Events)
- 直接將消息發送到特定客戶端(基於標識符)
- 廣播消息
UPDATE:
Config.sendMessage
添加要發送消息給單個客戶端Config.broadCast
加入到廣播消息authorizeIncomingConnection
授權客戶端,接受或拒絕連接tcpConnections
靜態提起加入,以保持tcpEvent來源
問題!
使用
tcpConnections
HashMap的好主意?!是我實施了一個好的授權方法嗎?!
Main.java
@SpringBootApplication
public class Main {
public static void main(final String[] args) {
SpringApplication.run(Main.class, args);
}
}
Config.java
@EnableIntegration
@IntegrationComponentScan
@Configuration
public class Config implements ApplicationListener<TcpConnectionEvent> {
private static final Logger LOGGER = Logger.getLogger(Config.class.getName());
@Bean
public AbstractServerConnectionFactory AbstractServerConnectionFactory() {
return new TcpNetServerConnectionFactory(8181);
}
@Bean
public TcpInboundGateway TcpInboundGateway(AbstractServerConnectionFactory connectionFactory) {
TcpInboundGateway inGate = new TcpInboundGateway();
inGate.setConnectionFactory(connectionFactory);
inGate.setRequestChannel(getMessageChannel());
return inGate;
}
@Bean
public MessageChannel getMessageChannel() {
return new DirectChannel();
}
@MessageEndpoint
public class Echo {
@Transformer(inputChannel = "getMessageChannel")
public String convert(byte[] bytes) throws Exception {
return new String(bytes);
}
}
private static ConcurrentHashMap<String, TcpConnection> tcpConnections = new ConcurrentHashMap<>();
@Override
public void onApplicationEvent(TcpConnectionEvent tcpEvent) {
TcpConnection source = (TcpConnection) tcpEvent.getSource();
if (tcpEvent instanceof TcpConnectionOpenEvent) {
LOGGER.info("Socket Opened " + source.getConnectionId());
tcpConnections.put(tcpEvent.getConnectionId(), source);
if (!authorizeIncomingConnection(source.getSocketInfo())) {
LOGGER.warn("Socket Rejected " + source.getConnectionId());
source.close();
}
} else if (tcpEvent instanceof TcpConnectionCloseEvent) {
LOGGER.info("Socket Closed " + source.getConnectionId());
tcpConnections.remove(source.getConnectionId());
}
}
private boolean authorizeIncomingConnection(SocketInfo socketInfo) {
//Authorization Logic , Like Ip,Mac Address WhiteList or anyThing else !
return (System.currentTimeMillis()/1000) % 2 == 0;
}
public static String broadCast(String message) {
Set<String> connectionIds = tcpConnections.keySet();
int successCounter = 0;
int FailureCounter = 0;
for (String connectionId : connectionIds) {
try {
sendMessage(connectionId, message);
successCounter++;
} catch (Exception e) {
FailureCounter++;
}
}
return "BroadCast Result , Success : " + successCounter + " Failure : " + FailureCounter;
}
public static void sendMessage(String connectionId, final String message) throws Exception {
tcpConnections.get(connectionId).send(new Message<String>() {
@Override
public String getPayload() {
return message;
}
@Override
public MessageHeaders getHeaders() {
return null;
}
});
}
}
MainController.java
@Controller
public class MainController {
@RequestMapping("/notify/{connectionId}/{message}")
@ResponseBody
public String home(@PathVariable String connectionId, @PathVariable String message) {
try {
Config.sendMessage(connectionId, message);
return "Client Notified !";
} catch (Exception e) {
return "Failed To Notify Client , cause : \n " + e.toString();
}
}
@RequestMapping("/broadCast/{message}")
@ResponseBody
public String home(@PathVariable String message) {
return Config.broadCast(message);
}
}
用法:
- 插座請求/響應模式
通知單個客戶端
http://localhost:8080/notify/{connectionId}/{message}
廣播
http://localhost:8080/broadCast/{message}
謝謝你,我更新了我的問題,你可以看看嗎? – Mojtabye
有趣的技術;哈希映射是好的(雖然你應該在'sendMessage'中檢查'null',因爲有競爭條件)。但是,您無法在發佈連接打開事件的線程(即「接受」線程(服務器套接字))上執行身份驗證。數據將在不同的線程上發送。這就是爲什麼我說你需要一個路由器通過認證邏輯在套接字上路由第一個請求。 –
你能解釋一下嗎?或者給我一個關於使用路由器的代碼片段? – Mojtabye