Reputation: 133
How to implement transfer control using "TCP urgent data" in Java.
I implemented a client-server application for transferring a file using the TCP protocol. Server is parallel. It is also necessary to implement transmission control using urgent data. I did not find a solution on Java on the Internet.
Server class:
import javafx.beans.binding.Bindings;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static final String FILE_PATH_SERVER = "C:\\Users\\anduser\\IdeaProjects\\Shafarenko_LR1\\src\\main\\resources\\fileServer.txt";
public static final File FILE_SERVER = new File(FILE_PATH_SERVER);
private ServerSocket serverSocket;
public void start(int port) throws IOException {
serverSocket = new ServerSocket(port);
while (true)
new ClientHandler(serverSocket.accept()).start();
}
public void stop() throws IOException {
serverSocket.close();
}
private static class ClientHandler extends Thread {
private Socket clientSocket;
private DataOutputStream out;
private FileInputStream in;
public ClientHandler(Socket socket) {
this.clientSocket = socket;
}
public void run() {
try {
out = new DataOutputStream(clientSocket.getOutputStream());
out.writeInt((int) FILE_PATH_SERVER.length());
} catch (IOException e) {
e.printStackTrace();
}
try {
in = new FileInputStream(FILE_PATH_SERVER);
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
byte buf[] = new byte[8];
int len = 0;
try {
len = in.read(buf);
} catch (IOException e) {
e.printStackTrace();
}
if (len == -1) {
break;
}
try {
out.write(buf, 0, len);
} catch (IOException e) {
e.printStackTrace();
}
try {
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Client class:
import org.apache.commons.lang3.RandomStringUtils;
import java.io.*;
import java.net.Socket;
public class Client {
private String generatedFileClient = RandomStringUtils.randomAlphanumeric(10) + ".txt";
private String FILE_PATH_CLIENT = "C:\\Users\\anduser\\IdeaProjects\\Shafarenko_LR1\\src\\test\\resources\\" + generatedFileClient;
private Socket clientSocket;
private FileOutputStream out;
private DataInputStream in;
private File fileCilent;
public File getFileClient() {
return new File(FILE_PATH_CLIENT);
}
public void getFile() throws IOException {
int i = 0;
int len;
byte buf[] = new byte[8];
int fileSize;
fileSize = in.readInt();
while (i < fileSize) {
len = in.read(buf);
if (len == -1) {
break;
}
i += len;
out.write(buf, 0, len);
out.flush();
}
out.close();
}
public void startConnection(String ip, int port) throws IOException {
clientSocket = new Socket(ip, port);
out = new FileOutputStream(FILE_PATH_CLIENT);
in = new DataInputStream(clientSocket.getInputStream());
}
public void stopConnection() throws IOException {
in.close();
out.close();
clientSocket.close();
}
}
Test:
public class TestClient {
@Test(threadPoolSize = 10, invocationCount = 1000, timeOut = 0)
public void givenClient() throws IOException, InterruptedException {
SoftAssert softAssert = new SoftAssert();
Client client = new Client();
client.startConnection("127.0.0.1", 555);
client.getFile();
softAssert.assertTrue(FileUtils.contentEquals(Server.FILE_SERVER, client.getFileClient()), "The files differ!");
client.stopConnection();
softAssert.assertAll();
}
}
Upvotes: 0
Views: 858
Reputation: 5055
From Harold's "Java Network Programming":
TCP includes a feature that sends a single byte of “urgent” data out of band. This data is sent immediately. Furthermore, the receiver is notified when the urgent data is received and may elect to process the urgent data before it processes any other data that has already been received. Java supports both sending and receiving such urgent data. The sending method is named, obviously enough, sendUrgentData():
public void sendUrgentData(int data) throws IOException
This method sends the lowest-order byte* of its argument almost immediately. If necessary, any currently cached data is flushed first.
How the receiving end responds to urgent data is a little confused, and varies from one platform and API to the next. Some systems receive the urgent data separately from the regular data. However, the more common, more modern approach is to place the urgent data in the regular received data queue in its proper order, tell the application that urgent data is available, and let it hunt through the queue to find it. By default, Java ignores urgent data received from a socket. However, if you want to receive urgent data inline with regular data, you need to set the OOBINLINE option to true using these methods: By default, Java ignores urgent data received from a socket. However, if you want to receive urgent data inline with regular data, you need to set the OOBINLINE option to true using these methods:
public void setOOBInline(boolean on) throws SocketException
public boolean getOOBInline() throws SocketException
The default for OOBINLINE is false. This code fragment turns OOBINLINE on, if it’s turned off:
if (!s.getOOBInline()) s.setOOBInline(true);
Once OOBINLINE is turned on, any urgent data that arrives will be placed on the socket’s input stream to be read in the usual way. Java does not distinguish it from nonurgent data. That makes it less than ideally useful, but if you have a particular byte (e.g., a Ctrl-C) that has special meaning to your program and never shows up in the regular data stream, then this would enable you to send it more quickly.
There are a lot of examples on GitHub of using sendUrgentData()
and setOOBInline()
. E.g. this.
* - remember that almost all implementations really can provide only one byte of "out-of-band data".
Read more:
Upvotes: 1