НАладь работу этих блоков:
package serverUtils;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;

public class Console {

public void start() throws IOException {
ConnectionManager connectionManager = new ConnectionManager(6789);

connectionManager.initialize();

Selector selector = Selector.open();
connectionManager.registerSelector(selector);

while (true) {
int readyChannelsCount = selector.selectNow();
if (readyChannelsCount == 0) {
continue;
}
Iterator<SelectionKey> selectedKeysIterator = selector.selectedKeys().iterator();
while (selectedKeysIterator.hasNext()) {
SelectionKey key = selectedKeysIterator.next();
selectedKeysIterator.remove();
connectionManager.processQuery(selector, key);
}
}
}
}

package serverUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.;
import java.nio.charset.StandardCharsets;

public class ConnectionManager {
private static final String ACK_MESSAGE_PREFIX = “<%s>Ack”;
static final int BUFFER_SIZE = 1024 * 1024;

ServerSocketChannel serverSocketChannel;
int port;

public ConnectionManager(int port) {
this.port = port;
}

public void initialize() throws IOException {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
System.out.println(“Server started on port " + port);
System.out.println(”============ * ============");
}

public void registerSelector(Selector selector) throws ClosedChannelException {
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}

public void processQuery(Selector selector, SelectionKey key) throws IOException {
if (!key.isValid()) {
return;
}
if (key.isAcceptable()) {
acceptConnection(key, selector);
} else if (key.isReadable()) {
handleRead(key);
}
}
private void acceptConnection(SelectionKey key, Selector selector) throws IOException {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel clientSocketChannel = serverSocketChannel.accept();
clientSocketChannel.configureBlocking(false);
// Attach new ConnectionContext instance to the selection key
ConnectionContext context = new ConnectionContext();
clientSocketChannel.register(selector, SelectionKey.OP_READ, context);

System.out.println(“Accepted connection from " + clientSocketChannel.getRemoteAddress());
}

private void handleRead(SelectionKey key) throws IOException {
SocketChannel clientSocketChannel = (SocketChannel) key.channel();
ConnectionContext connectionContext = (ConnectionContext) key.attachment();

System.out.println(connectionContext);

if (connectionContext == null) {
connectionContext = new ConnectionContext();
key.attach(connectionContext);
}

ByteBuffer buffer = connectionContext.buffer;
int bytesRead = clientSocketChannel.read(buffer);

if (bytesRead < 0) {
System.out.println(“Closed connection with " + clientSocketChannel.getRemoteAddress());
clientSocketChannel.close();
key.cancel();
System.out.println(”============ * ============”);
return;
}

buffer.flip();

// handle file transmission
if (connectionContext.fileStarted) {
// check if we need more data to continue reading the file
if (connectionContext.fileName != null && connectionContext.fileLength >= 0 &&
buffer.remaining() >= connectionContext.fileLength + Long.BYTES) {

// read the file contents
byte[] fileContent = new byte[connectionContext.fileLength];
buffer.get(fileContent);

// check the separator
connectionContext.separator = buffer.getLong();
if (connectionContext.separator != 0L) {
throw new RuntimeException(“Invalid separator”);
}

// save the file and send an acknowledgement
saveFile(connectionContext.fileName, fileContent);
sendAck(clientSocketChannel, connectionContext.fileName);

// reset context for next file transfer
connectionContext.fileStarted = false;
connectionContext.fileCompleted = true;
connectionContext.fileName = null;
connectionContext.fileLength = -1;

// handle any remaining data in buffer
if (buffer.remaining() > 0) {
handleRead(key);
return;
}
}
} else {
// read the header of the file transfer
while (buffer.hasRemaining() && !connectionContext.fileStarted) {
// read the name length
if (connectionContext.fileName == null && buffer.remaining() >= Integer.BYTES) {
int nameLength = buffer.getInt();
byte[] nameBytes = new byte[nameLength];
buffer.get(nameBytes);
connectionContext.fileName = new String(nameBytes, StandardCharsets.UTF_8);
}

// read the file length
if (connectionContext.fileLength < 0 && buffer.remaining() >= Integer.BYTES) {
connectionContext.fileLength = buffer.getInt();
if (connectionContext.fileLength < 0) {
throw new RuntimeException(“Invalid file length”);
}
connectionContext.fileStarted = true;

// check if we need more data to continue reading the file
if (buffer.remaining() < BUFFER_SIZE) {
buffer.compact();
return;
}
}
}
}

// handle file transmission continued with remaining data in buffer
if (connectionContext.fileStarted && !connectionContext.fileCompleted &&
buffer.remaining() >= connectionContext.fileLength + Long.BYTES) {

// read the file contents
byte[] fileContent = new byte[connectionContext.fileLength];
buffer.get(fileContent);

// check the separator
connectionContext.separator = buffer.getLong();
if (connectionContext.separator != 0L) {
throw new RuntimeException(“Invalid separator”);
}

// save the file and send an acknowledgement
saveFile(connectionContext.fileName, fileContent);
sendAck(clientSocketChannel, connectionContext.fileName);

// reset context for next file transfer
connectionContext.fileStarted = false;
connectionContext.fileCompleted = true;
connectionContext.fileName = null;
connectionContext.fileLength = -1;

// handle any remaining data in buffer
if (buffer.remaining() > 0) {
handleRead(key);
return;
}
}

buffer.compact();
}

private void saveFile(String filename, byte[] fileContent) throws IOException {
File file = new File(“files\” + filename);

System.out.println("Saving file " + filename);

try (FileOutputStream outputStream = new FileOutputStream(file, true)) {
int offset = 0;
while (offset < fileContent.length) {
int bytesToWrite = Math.min(BUFFER_SIZE, fileContent.length - offset);
outputStream.write(fileContent, offset, bytesToWrite);
offset += bytesToWrite;
}
outputStream.flush();
}
System.out.println(“File " + filename + " saved successfully”);
}


private void sendAck(SocketChannel clientSocketChannel, String filename) throws IOException {
String ackMessage = String.format(ACK_MESSAGE_PREFIX, filename);
byte[] ackMessageBytes = ackMessage.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(ackMessageBytes.length + Integer.BYTES);
buffer.putInt(ackMessageBytes.length);
buffer.put(ackMessageBytes);
buffer.flip();

while (buffer.hasRemaining()) {
clientSocketChannel.write(buffer);
}

System.out.println("Sent acknowledgement for " + filename);
buffer.clear(); // Очищаем буфер перед чтением новых данных
}
}

package serverUtils;

import java.nio.ByteBuffer;

public class ConnectionContext {
public String fileName;
public ByteBuffer buffer;
public int fileLength = -1;
public long separator = 0L;
public boolean fileStarted = false;
public boolean fileCompleted = false;

public ConnectionContext() {
this.buffer = ByteBuffer.allocate(ConnectionManager.BUFFER_SIZE);
}
}

package clientUtils;

import java.io.;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;


public class ConnectionManager {
String ip;
int port;
SocketChannel socketChannel;

public ConnectionManager(String ip, int port) {
this.ip = ip;
this.port = port;
}

void makeRequest(File file, FileInputStream fis) throws IOException {
// connect();
sendFile(file, fis);
receiveConfirmation();
// closeConnection();
}
void connect() throws IOException {
System.out.println(“Connected to the server”);
socketChannel = SocketChannel.open(new InetSocketAddress(ip, port));
socketChannel.configureBlocking(true);
}

void closeConnection() throws IOException {
socketChannel.close();
System.out.println(“Connection closed”);
}
private void sendFile(File file, FileInputStream fis) throws IOException {

// Создаем байтовый массив для передачи имени файла и его длины
byte[] nameBytes = file.getName().getBytes(StandardCharsets.UTF_8);
ByteBuffer nameLengthBuffer = ByteBuffer.allocate(Integer.BYTES).putInt(nameBytes.length);
nameLengthBuffer.flip();

// Отправляем длину имени файла и само имя
socketChannel.write(nameLengthBuffer);

ByteBuffer nameBuffer = ByteBuffer.wrap(nameBytes);
socketChannel.write(nameBuffer);

// Отправляем длину файла
int fileLength = (int) file.length();
ByteBuffer fileLengthBuffer = ByteBuffer.allocate(Integer.BYTES).putInt(fileLength);
fileLengthBuffer.flip();
socketChannel.write(fileLengthBuffer);

// Определяем размер куска
int chunkSize = 1024;
byte[] buffer = new byte[chunkSize];

// Читаем данные из файла по кускам и отправляем их
int totalBytesRead = 0;
while (totalBytesRead < fileLength) {
int bytesRead = fis.read(buffer, 0, Math.min(chunkSize, fileLength - totalBytesRead));
if (bytesRead > 0) { // если прочитали что-то из файла
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, bytesRead);
socketChannel.write(byteBuffer); // отправляем текущий кусок
totalBytesRead += bytesRead; // увеличиваем количество переданных байт
}
}
socketChannel.write(ByteBuffer.allocate(Long.BYTES)); // разделитель

fis.close();

System.out.println(“File " + file.getName() + " sent successfully”);
}

private void receiveConfirmation() throws IOException {
// Читаем длину сообщения
ByteBuffer lengthBuffer = ByteBuffer.allocate(Integer.BYTES);
socketChannel.read(lengthBuffer);
lengthBuffer.flip();
int messageLength = lengthBuffer.getInt();

// Читаем само сообщение
ByteBuffer messageBuffer = ByteBuffer.allocate(messageLength);
int bytesRead = 0;
while (bytesRead < messageLength) {
bytesRead += socketChannel.read(messageBuffer);
}
messageBuffer.rewind();
byte[] messageBytes = new byte[messageBuffer.remaining()];
messageBuffer.get(messageBytes);
String message = new String(messageBytes, StandardCharsets.UTF_8);

System.out.println("Received file: " + message);
}
}