java.net.Socket.setTrafficClass(int tc)
TOS (type-of-service) 是IP 报文协议头的一个8位字段,用于配置此类流量的优先级。
Java API 中,java.net.Socket.setTrafficClass(int tc) 接口用于配置TOS。
由于TOS 与DSCP 的兼容性,此API 也是用于DSCP 配置。
DSCP(Differentiated Services Codepoint)是TOS 字段的高6 位,低2 位补0;
AF
保证转发(Assured Forwarding,AF)由RFC2597 对CS1~CS4 进行进一步定义。它使用第3和第4比特做丢弃优先级标志。
- 01-低丢弃优先级;
- 10-中丢弃优先级;
- 11-高丢弃优先级。
这样,在同一类数据中,又根据被丢弃的可能性划分出3档。下表列出了AF服务等级及其对应的DSCP值:
CS1 | CS2 | CS3 | CS4 | ||
---|---|---|---|---|---|
Lowdrop | AF11 | AF21 | AF31 | AF41 | |
001010 | 010010 | 011010 | 100010 | ||
Mediumdrop | AF12 | AF22 | AF32 | AF42 | |
001100 | 010100 | 011100 | 100100 | ||
Highdrop | AF13 | AF23 | AF33 | AF43 | |
001110 | 010110 | 011110 | 100110 |
实验
本实验我们配置DSCP 为AF41(0b100010 = 0x22 = 34,对应TOS:0b10001000 = 0x88 = 136)
如下两个java 文件分别作为客户端和服务端代码,编译执行:
# javac Client.java
# javac Server.java
# java -Djava.net.preferIPv4Stack=true Server 7777 136
Starting server....
Client:172.28.200.100 is accepted.
Test start.
# java -Djava.net.preferIPv4Stack=true Client 10.198.245.86 7777 136
Test start.
1000 pingpongs, Average Time(us): 2087
执行期间通过tcpdump 抓包:
# tcpdump port 7777 -nnvvS
......
16:27:01.224518 IP (tos 0x88, ttl 64, id 4821, offset 0, flags [DF], proto TCP (6), length 42)
172.28.200.100.60918 > 10.198.245.86.7777: Flags [P.], cksum 0x74ba (incorrect -> 0x1449), seq 1936351735:1936351737, ack 1871775163, win 58, length 2
16:27:01.226615 IP (tos 0x88, ttl 57, id 62839, offset 0, flags [DF], proto TCP (6), length 42)
10.198.245.86.7777 > 172.28.200.100.60918: Flags [P.], cksum 0x1447 (correct), seq 1871775163:1871775165, ack 1936351737, win 58, length 2
......
<-- 可以看到数据部分tos 为0x88(默认为0),说明设置生效。
ping 时延测试如下图:
测试代码
//File: Client.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) {
String ip = args[0];
int port = Integer.parseInt(args[1]);
int tos = Integer.parseInt(args[2]);
try {
Socket s = new Socket(ip, port);
s.setTrafficClass(tos);
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
bw.write("Test start.\n");
bw.flush();
String hiMsg = br.readLine();
System.out.println(hiMsg);
long now_us = 0;
long sum_us = 0;
long begin_us = 0;
int num = 1000;
for (int i = 0; i < num; i++) {
bw.write(i);
bw.flush();
begin_us = System.nanoTime() / 1000;
int msg = br.read();
now_us = System.nanoTime() / 1000;
sum_us += now_us - begin_us;
//System.out.println("Server: " + msg + ", us:" + sum_us);
}
System.out.println(num + " pingpongs, Average Time(us): " + (sum_us / num));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// File: Server.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
int tos = Integer.parseInt(args[1]);
while (true) {
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
System.out.println("Starting server....");
Socket s = ss.accept();
s.setTrafficClass(tos);
System.out.println("Client:" + s.getInetAddress().getHostAddress() + " is accepted.");
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String hiMsg = br.readLine();
System.out.println(hiMsg);
bw.write(hiMsg + "\n");
bw.flush();
int num = 100000;
for (int i = 0; i < num; i++) {
int msg = br.read();
//System.out.println("Client:" + msg);
bw.write(msg);
bw.flush();
}
} catch (Throwable e) {
//e.printStackTrace();
System.out.println(e);
try {
ss.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
}