TCP建立连接释放链接、截断二进制指数避让、CRC校验

1.      TCP建立链接


图一

客户端A主动打开链接,服务器B被动打开链接。B的TCP服务器进程先创建传输控制块TCB,准备接收客户端链接请求,然后服务B进入到了LISTEN状态,等待客户端链接。

客户端A首先建立TCB,然后向服务器B发送连接请求报文段,在报文的首部SYN=1,同时选择一个初始序号seq=x。TCP的SYN报文段不能携带数据,但是要消耗一个序号。此时客户端A进入SYN-SENT状态(请求链接状态)。

服务器B接到链接请求后,若同意建立链接,则向A发送确认。在确认报文中把SYN和ACK都置1,确认号为ack+1,初始化序列为seq=y,消耗掉一个序列,且不能携带数据。此时服务器B进入到SYN-RCVD状态(半断开连接)。

客户端A收到服务器B的确认后,还要向B发送确,此时ACK=1,seq=x+1,ack=y+1。ACK = 1可以携带数据,若没有携带数据则不消耗序号。客户端A进入ESTAB-LISHED状态。服务器B收到确认信号后进入ESTAB-LISHED状态。

2.      TCP链接释放


图二

在数据传输结束后,通信的双方都可以释放链接。在A和B都处于ESTAB-LISHED状态。A的应用进程先向其TCP发出链接释放报文段,并停止在发送数据,主动关闭tcp链接。A把链接释放报文段的FIN置1,seq=u(u=前面已经发送数据的最后一个字节+1)。此时A进入FIN-WAIT-1(终止等待1)状态,等在B的确认。FIN报文段不能携带数据,但要消耗一个序号。

B接收到链接释放报文后即发出确认,确认号是ack= u+1,seq = u(u=前面已经发送数据的最后一个报文的序号+1)。然后B进入CLOSE-WAIT(关闭等待)状态。TCP服务器进程通知高层应用进程,因此从A到B方向的链接就被释放了,此时TCP链接处于半关闭状态。

A收到B的确认后,就进入FIN-WAIT2(终止等待2)状态,等待B发出的链接释放报文。

若B已经没有数据要想A发送,其应用进程就通知TCP释放链接。此时B发出的链接释放报文必须使FIN=1。ack = u+1,seq=w(w=前面已经发送数据的最后一个字节的序号+1)。这时B进入LAST-ACK(最后确认)状态。

A收到B的链接释放报文,必须对其发出确认。ACK=1,ack = w+1,seq = u+1。然后进入TIME-WAIT(时间等待)状态。必须等到时间等待计数器设置的时间2MSL后才进入closed状态。

时间等待是为了保证A发送的最后一个ACK能够到达B。

 

截断二进制指数避让:

①  协议规定基本退让时间为争用时间的2τ,具体的争用时间为51.2μS。

②  从离散的整数集合[0,1…2^k-1]中抽取一个随机数R,重传时间就是R倍的争用时间。K的计算公式为:K=min(重传次数,10);

③  当重传次数超过16次时,则丢弃该帧并向高层汇报。

 

循环冗余码(CRC校验):

M=101001   P=1101      2^n M = 101001000    冗余码=001



图三

在Java中,使用TCP协议发送带十六进制数据和CRC校验的指令通常涉及以下几个步骤: 1. **创建套接字连接**: 首先,你需要创建一个`Socket`对象,用于客户端或服务器端建立TCP连接。 ```java Socket socket = new Socket(host, port); ``` 2. **编码十六进制数据**: 使用`Integer.toHexString()`将原始数据转换成十六进制字符串,然后添加到你要发送的数据包中。 ```java byte[] rawData = ...; // 要发送的原始数据 String hexData = String.format("%02x", Arrays.stream(rawData).mapToObj(b -> b & 0xff).collect(Collectors.toList())); ``` 3. **计算CRC校验**: 确定一个合适的CRC,如Java内置的`java.util.zip.CRC32`。首先计算原始数据的CRC值,然后将其转换为十六进制字符串。 ```java CRC32 crcCalculator = new CRC32(); crcCalculator.update(rawData); int checksum = (int) crcCalculator.getValue(); String hexChecksum = Integer.toHexString(checksum); ``` 4. **构建完整的消息**: 将十六进制数据和CRC结合在一起形成完整的消息。 ```java StringBuilder message = new StringBuilder(); message.append(hexData).append(":").append(hexChecksum); ``` 5. **封装和发送数据**: 创建一个新的`DatagramPacket`或`OutputStream`来发送消息,包括前导的头部信息以及实际的十六进制数据。 ```java // 如果使用DatagramPacket DatagramPacket packet = new DatagramPacket(message.toString().getBytes(), message.length(), address, port); socket.send(packet); // 如果使用OutputStream PrintWriter outputStream = new PrintWriter(socket.getOutputStream(), true); outputStream.println(message.toString()); outputStream.flush(); ``` 6. **接收和解析数据**: 对于接收端,创建一个`BufferedReader`从输入流读取数据,并按照约定的格式分割出十六进制部分和CRC。 ```java BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String receivedMessage = reader.readLine(); String[] parts = receivedMessage.split(":", 2); // 分割数据 hexData = parts[0]; hexChecksum = parts[1]; ``` 7. **验证CRC**: 再次计算收到数据的CRC值并与接收到的进行比较,确认数据是否正确。 ```java crcCalculator.update(receivedData); int calculatedChecksum = (int) crcCalculator.getValue(); if (calculatedChecksum == Integer.parseInt(hexChecksum, 16)) { // 数据校验通过 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值