이전까지 Socket 객체를 생성하고 이를 활용하는 echo server도 띄워서 정상적으로 동작하는 것을 확인했었다. 이대로 끝낸다면 아쉽다. stream이라는 리소스를 잡고 있는 객체인만큼 싱글톤으로 프레임워크 차원에서 관리하기 위해 Spring bean으로 등록해보자.
전체 코드
SocketProvider Bean
package com.example.test;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.newsclub.net.unix.AFSocketAddress;
import org.newsclub.net.unix.AFUNIXSocket;
import org.newsclub.net.unix.AFUNIXSocketAddress;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URI;
@Slf4j
@Component
public class SocketProvider {
private static final String SOCKET_PATH = "/tmp/my_unix_socket.sock";
private static final int BUFFER_SIZE = 256;
private AFUNIXSocket sock;
private OutputStream out;
private InputStream in;
@PostConstruct
public void connect() throws IOException {
SocketAddress endpoint = getSocketAddress(SOCKET_PATH);
sock = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of(endpoint));
out = sock.getOutputStream();
in = sock.getInputStream();
log.info("UDS Connected Completely to {}", endpoint);
}
@PreDestroy
public void disconnect() throws IOException {
if (sock != null && !sock.isClosed()) {
sock.close();
log.info("Disconnected from server on " + SOCKET_PATH);
}
}
// Need for custom return value for error handling
public boolean isValid() {
if (sock == null) {
return false;
} else if (!sock.isConnected()) {
return false;
}
return true;
}
public void reconnect() throws IOException {
if (this.isValid()) {
return;
}
SocketAddress endpoint = getSocketAddress(SOCKET_PATH);
sock = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of(endpoint));
out = sock.getOutputStream();
in = sock.getInputStream();
}
public String sendMessage(String message) throws IOException {
if (sock == null || !sock.isConnected()) {
log.info("UDS NOT CONNECTED!!!");
throw new IOException("UDS Not Connected");
}
log.info("Now writing string({}) to the server...", message);
out.write(message.getBytes());
out.flush();
byte[] buffer = new byte[BUFFER_SIZE];
int numRead = in.read(buffer);
if (numRead > 0) {
return new String(buffer, 0, numRead);
} else {
return null;
}
}
private SocketAddress getSocketAddress(String socketName) throws IOException {
if (socketName.startsWith("file:")) {
// demo only: assume file: URLs are always handled by AFUNIXSocketAddress
return AFUNIXSocketAddress.of(URI.create(socketName));
} else if (socketName.contains(":/")) {
// assume URI, e.g., unix:// or tipc://
return AFSocketAddress.of(URI.create(socketName));
}
int colon = socketName.lastIndexOf(':');
int slashOrBackslash = Math.max(socketName.lastIndexOf('/'), socketName.lastIndexOf('\\\\'));
if (socketName.startsWith("@")) {
// abstract namespace (Linux only!)
return AFUNIXSocketAddress.inAbstractNamespace(socketName.substring(1));
} else if (colon > 0 && slashOrBackslash < colon && !socketName.startsWith("/")) {
// assume TCP socket
String hostname = socketName.substring(0, colon);
int port = Integer.parseInt(socketName.substring(colon + 1));
return new InetSocketAddress(hostname, port);
} else {
// assume unix socket file name
return AFUNIXSocketAddress.of(new File(socketName));
}
}
}
MessageController
package com.example.test;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class MessageController {
private final SocketProvider socketProvider;
@PostMapping("/send")
public String sendMessage(@RequestBody MessageRequest request) throws IOException {
// Send a message and read the response
log.info("Client(Spring Boot) request \\"{}\\" to Server(c)", request.getMessage());
String response = socketProvider.sendMessage(request.getMessage());
log.info("Server(c) response \\"{}\\" to Client(Spring Boot)", response);
return response;
}
}
실행 로그 관찰
Boot시 UDS Connect 로그 확인
echo message 관찰
'개발일기 > Spring + Unix Domain Socket' 카테고리의 다른 글
[Spring + UDS] 6. Spring property 분리 (0) | 2024.08.08 |
---|---|
[Spring + UDS] 4. Spring Boot Client 구현 (0) | 2024.08.08 |
[Spring + UDS] 3. C demo Server (0) | 2024.08.08 |
[Spring + UDS] 2. JUNIXSocket (0) | 2024.08.08 |
[Spring + UDS] 1. 사건의 발단… (0) | 2024.08.08 |
댓글