[英]Sending TCP urgend data through the socket in Java
Java中如何使用“TCP紧急数据”实现传输控制。
我实现了一个客户端-服务器应用程序,用于使用 TCP 协议传输文件。 服务器是并行的。 还需要使用紧急数据来实现传输控制。 我没有在互联网上找到有关 Java 的解决方案。
服务器类:
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();
}
}
}
}
客户端类:
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();
}
}
测试:
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();
}
}
来自 Harold 的“ Java 网络编程”:
TCP 包含一个功能,可以在带外发送单个字节的“紧急”数据。 该数据将立即发送。 此外,接收器在接收到紧急数据时得到通知,并且可以选择在处理已经接收到的任何其他数据之前处理紧急数据。 Java 支持发送和接收此类紧急数据。 发送方法被命名为,很明显,sendUrgentData():
public void sendUrgentData(int data) throws IOException
此方法几乎立即发送其参数的最低字节* 。 如有必要,首先刷新任何当前缓存的数据。
接收端如何响应紧急数据有点混乱,并且从一个平台和 API 到另一个不同。 一些系统将紧急数据与常规数据分开接收。 然而,更常见、更现代的方法是将紧急数据按照正确的顺序放置在常规接收数据队列中,告诉应用程序紧急数据可用,并让它在队列中寻找它。 默认情况下,Java 会忽略从套接字接收到的紧急数据。 但是,如果要接收与常规数据内联的紧急数据,则需要使用以下方法将 OOBINLINE 选项设置为 true: 默认情况下,Java 会忽略从套接字接收的紧急数据。 但是,如果要接收与常规数据内联的紧急数据,则需要使用以下方法将 OOBINLINE 选项设置为 true:
public void setOOBInline(boolean on) throws SocketException
public boolean getOOBInline() throws SocketException
OOBINLINE 的默认值为 false。 如果 OOBINLINE 已关闭,此代码片段将打开 OOBINLINE:
if (!s.getOOBInline()) s.setOOBInline(true);
一旦 OOBINLINE 被打开,任何到达的紧急数据都将被放置在套接字的输入流上,以便以通常的方式读取。 Java 不会将其与非紧急数据区分开来。 这使得它不太理想,但是如果您有一个对您的程序具有特殊意义的特定字节(例如,Ctrl-C)并且从未出现在常规数据流中,那么这将使您能够更快地发送它.
GitHub 上有很多使用sendUrgentData()
和setOOBInline()
的例子。 例如这个。
* - 请记住,几乎所有的实现实际上只能提供一个字节的“带外数据” 。
阅读更多:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.