/*接收分组头*/ //1.不接收超时. 2.接收成功,会调用发送分组头确认包 public Rdh_return ReceiveDatagramHead(int numberRandom) { byte[] buffer = new byte[FilePropertyTip[0]]; //DatagramPacket packet = null; Rdh_return rdh = new Rdh_return(); //设置不接收超时 udpReceiveClient.Client.ReceiveTimeout = 0; while (true) { try { //packet = new DatagramPacket(buffer, buffer.length);//,InetAddress.getByName(yourAddress),yourPort ByteChange.CleanByte(buffer); //socket.receive(packet); //receiveState.addHaveReceiveBytes(packet.getLength()); buffer = udpReceiveClient.Receive(ref host); //检查分组头标识 //String str = new String(buffer, HeadTip[1], 4); String str = Encoding.Default.GetString(buffer, HeadTip[1], 4); //if (!str.equals(datagramHead)) if (!datagramHead.Equals(str)) { /*既然不是分组头,重新接收是肯定的.只不过,有些情况,需要处理一下再重新接收*/ //如果是开始传输包 //if (str.equals(datagramStart)) if (datagramStart.Equals(str)) { int num = ByteChange.ByteToInt(buffer, StartTip[2]); if (num == numberRandom) { SendStartAck(numberRandom); // System.out.println("在分组头中接收到开始传输包"); continue; } } //如果是发送完毕包 //if (str.equals(datagramFinish)) if (datagramFinish.Equals(str)) { //先检其次随机数 if (ByteChange.ByteToInt(buffer, FinishTip[2]) == numberRandom) { //检验是不是上一次的发送完毕包 //如果是的,说明上次发的0请求重发包没发成功 //先检查其块随机数是不是上一次的 if (randomStack.GetLast() != -1 && ByteChange.ByteToInt(buffer, FinishTip[3]) == randomStack.GetLast()) { //再检查其小随机数,是不是上次的(即最后一次发过来的) if (littleRandomStack != null) { //如果littelRandomStack是null,说明这是第一次接收分组头,当然不可能要重发 if (littleRandomStack.GetLast() == ByteChange.ByteToInt(buffer, FinishTip[4])) { //如果小随机数也匹配,则发送上次的0请求重发包 if (lastReqAgainBuffer != null) { //socket.send(lastReqAgain); udpReceiveClient.Send(lastReqAgainBuffer.ToArray(), lastReqAgainBuffer.Count, host); } } } } } } //如果是传输结束包,则将0分组数量填充入rdh,然后返回 //if (str.equals(datagramStop)) if (datagramStop.Equals(str)) { rdh.Number = 0; return(rdh); } continue; } //检查该包是否完整 //str = new String(buffer, HeadTip[5], 4); str = Encoding.Default.GetString(buffer, HeadTip[5], 4); //if (!str.equals(datagramTail)) if (!datagramTail.Equals(str)) { continue; } //检查完毕,获取随机数 rdh.Random = ByteChange.ByteToInt(buffer, HeadTip[3]); //获取分组数量 rdh.Number = ByteChange.ByteToShort(buffer, HeadTip[4]); SendDatagramHeadAck(numberRandom, rdh.Random); break; } catch (Exception ex) { //MessageBox.Show(ex.ToString()); // Logger.getLogger(ReceiveLittle.class.getName()).log(Level.SEVERE, null, ex); //logger.error("{}", ex); } } return(rdh); }
/*接收一次分组*/ //返回值为该数组中数据的长度.并且,此函数进行传送结束的检查.发现结束,返回-1 public int ReceiveGroup(int numberRandom, byte[] buffer) { //接收分组头 Rdh_return rdh = ReceiveDatagramHead(numberRandom); // System.out.println("收到分组头,随机数:"+rdh.random+",分组数量:"+rdh.number); //记下随机数及分组数量 //int random = rdh.random; //int number = rdh.number; int random = rdh.Random; int number = rdh.Number; if (number == 0) { return(-1); } randomStack.Add(random); littleRandomStack = new CircleStack(100); //设定数据总长度 int lengthAll = 0; //由于只有最后一组的数据长度不是dataLength,所以,先计算前number-1个分组的总长度 lengthAll = dataLength * (number - 1); //用于记录成功接收了哪些分组 bool[] receiveTip = new bool[number]; for (int i = 0; i < number; i++) { receiveTip[i] = false; } //预先计算各组应存入buffer的起始下标 //由于除了最后一组,其它组的数据长度一定是dataLength.所以计算起始下标非常简单 int[] startTip = new int[number]; for (int i = 0; i < number; i++) { startTip[i] = i * dataLength; } //进入大循环,即连续去接收分组,直到所有分组完毕 while (true) { int result = GetDatagramData(numberRandom, random, buffer, receiveTip, startTip); // System.out.println("收到分组包"+result); //如果接收到的是一个分组.要记录其长度.由于,除了最后一组,其他的长度一定是dataLength //所以,如果这个length不是dataLength,说明是最后一组的长度 if (result > 0) { if (result != dataLength) { lengthAll += result; } continue; } //如果接收到是分组头 else if (result == -2) { //发送分组头确认包,然后循环 SendDatagramHeadAck(numberRandom, random); continue; } //如果是新的发送完毕包 else if (result == -3) { //发送请求重发包 //在发送请求重发包的时候,是要检查是否全部成功接收的,所以,这里不再重新检查,而是使用它检查的结果 bool flag = SendDatagramReqAgain(numberRandom, random, littleRandomStack.GetLast(), receiveTip); //System.out.println("发送请求重发包"); if (flag) { break; } continue; } //如果是上次的发送完毕包 else if (result == -4) { //如果上次发送的不是0请求重发包,则重发 //非0请求重发包的长度,一定是1018 //System.out.println("接收到上次的发送完毕包:"); try { if (lastReqAgainBuffer.Count == ReqAgainTip[0]) { //System.out.println("重发非0请求重发包"); //socket.send(lastReqAgain); udpReceiveClient.Send(lastReqAgainBuffer.ToArray(), lastReqAgainBuffer.Count, host); } } catch (Exception ex) { log.Error(ex.ToString()); //MessageBox.Show(ex.ToString()); // Logger.getLogger(ReceiveLittle.class.getName()).log(Level.SEVERE, null, ex); //logger.error("{}", ex); } continue; } } //这里有个很蛋疼的问题.由于不确定最后一组是否完整,只有在接收到最后一个分组时才知道其数据长度 //而接收分组是在单独的函数中完成,函数返回的是接收的数据长度.在循环中,如果发现数据长度不是dataLength //就认为它是最后一组,并将其长度加入lengthAll.但是,有一个严重的问题,因为,每个块,只有最后一个块的最后一个 //分组的数据长度可能不是dataLength.所以,前面的块,在进行计算的时候,有会忽略它最后一组的长度.导致以后的块 //连续错误 if (lengthAll == (number - 1) * dataLength) { lengthAll += dataLength; } return(lengthAll); }