在数据链路层中,帧的大小各式各样,怎样把不同的帧区分开来?

字节填充就是用来干这个事情的。它的实现原理很简单,就是在每个帧的开头和结尾加上一个8位的标识F,用这个标识来区分每一个帧。

那么问题来了,如果帧本身的内容就包含这个标识F呢?也不复杂,可以类比正则表达式,用转义字符修饰普通的字符F就可以了,这里我们同样用一个8位标识E作为转义字符,你可能又会问,那如果帧本身内容也包含这个转义字符E呢?我们在转义字符前面再加上一个转义字符即可。

举个例子:

1
2
3
4
5
6
7
8
9
发送端将要发送的原始内容 : 
DDEDFFDE
字符填充之后的内存变为 :
FDDEEDEFEFDEEF

接收端接收到的内容 :
FDDEEDEFEFDEEF
还原成原本的内容 :
DDEDFFDE

用Java实现客户端与服务端
  • 客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Java Code for Byte_Stuffing Sender
package byte_stuffing;
import java.io.*;
import java.util.*;
import java.net.*;

public class Byte_Stuffing_Client {
public static void main(String args[]) throws IOException
{
InetAddress ip = InetAddress.getLocalHost();
int port = 45678;
Scanner sc = new Scanner(System.in);

// Opens a socket for connection
Socket s = new Socket(ip, port);

// Declaring I/O Streams
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());

while (true) {
System.out.println("Enter the Message to be Sent : ");
String data = sc.nextLine();
String res = new String();

// Data in each frame is stuffed by 'F' at beginning and end
data = 'F' + data + 'F';
for (int i = 0; i < data.length(); i++) {

// Stuff with 'E' if 'F' is found in the data to be sent
if (data.charAt(i) == 'F' && i != 0 && i != (data.length() - 1))
res = res + 'E' + data.charAt(i);

// Stuff with 'E' if 'E' is found in the data to be sent
else if (data.charAt(i) == 'E')
res = res + 'E' + data.charAt(i);
else
res = res + data.charAt(i);
}

System.out.println("The data being sent (with byte stuffed) is : " + res);

// Send the data to the receiver
dos.writeUTF(res);
System.out.println("Seding Message....");
if (dis.readUTF().equals("success"))
System.out.println("Thanks for the Feedback Server!!");

// End Messaging
dos.writeUTF("bye");
break;
}

// Close all connections
s.close();
dis.close();
dos.close();
}
}


  • 服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Java code for Byte_Stuffing Receiver
package byte_stuffing;
import java.io.*;
import java.net.*;

public class Byte_Stuffing {
public static void main(String[] args) throws IOException
{
// Opens a socket for connection
ServerSocket servsock = new ServerSocket(45678);

// Used to block until a client connects to the server
Socket socket = servsock.accept();

// Declaring I/O Streams
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

while (true) {
String out = new String();
// Used to read the data sent by client
String res = dis.readUTF();
System.out.println("Message Received...Successfully!!!");
System.out.println("The Stuffed Message is : " + res);

for (int i = 1; i < res.length() - 1; i++) {

// If data contains a 'D' or 'F' do not unstuff it
if (res.charAt(i) == 'D' || res.charAt(i) == 'F')
out = out + res.charAt(i);

// If data contains 'E' followed by 'E', de-stuff the former 'E'
else if (res.charAt(i) == 'E' && res.charAt(i + 1) == 'E') {
out = out + 'E';
i++;
}
}
System.out.println("The Destuffed Message is : " + out);
dos.writeUTF("success");
String ch = dis.readUTF();
if (ch.equals("bye")) {
System.out.println("Messaging is over.....EXITING");
break;
}
}

// Closing all connections
socket.close();
dis.close();
dos.close();
}
}

这里要注意一点,服务端应该先于客户端启动,因为服务端要先开启一个socket客户端才能进行连接


本文作者:oldmee
本文链接:https://oldmee.github.io/2015/08/23/Byte-Stuffing-using-Java/
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。