⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.c

📁 完整的TCP/IP源代码,绝对好用
💻 C
📖 第 1 页 / 共 2 页
字号:
   REMAINING = len;
   SENT = 0;

   if(conxn[nr].his_window > 1300) MIN_PACKET_SIZE = 1300;  //获得每个TCP包的最小长度
   else MIN_PACKET_SIZE = conxn[nr].his_window;
   if(MIN_PACKET_SIZE ==0)
   {
     printf("his window is 0\n");
	 return 0;


   }

   while((REMAINING != 0) && (SENT != conxn[nr].his_window)) //
   {
     if(REMAINING > MIN_PACKET_SIZE)   //这是判断是否已经传送数据的末尾
     {
       one_send_len = MIN_PACKET_SIZE; //
     }
     else one_send_len = REMAINING;

     if(conxn[nr].his_window < SENT+one_send_len) 
     {
       one_send_len = conxn[nr].his_window - SENT; //这里是发送剩余部分数据,因为已经到了对方窗口的极限
     }
     tcp_send_1_packet(buf+SENT,one_send_len,nr); //将这一包传送出去
     REMAINING -= one_send_len;
     SENT += one_send_len;   //调整已经传送的数据的长度。

     conxn[nr].timer = TCP_TIMEOUT;
	 conxn[nr].my_sequence += one_send_len; // 调整SEQ
	 
   }
   return SENT; //返回已经传送的数据长度
}

//******************************************
// 找一个空闲的连接,并返回这个连接的号码.
//
UINT8 find_leisure_connection()
{
  UINT8 i;
  for(i=0;i<MAX_SOCKET_NUM;i++)
  {
    if(conxn[i].state == STATE_CLOSED) return i;
  }
  return NO_CONNECTION;
}
//*************************************************************
//
// 把收到的数据送往连接的接收缓冲区,并调整接收WINDOW的大小
// 接收缓冲是循环的
//*************************************************************

void conxn_save_data(UINT8 nr,UINT8 *SRC,UINT16 data_len)
{
  UINT16 i;
  for(i=0;i<data_len;i++)
  {
    conxn[nr].inbuf[conxn[nr].inbuf_tail] = *(SRC+i);
    conxn[nr].inbuf_tail ++;

	conxn[nr].inbuf_tail &= max_mm; //循环存放
  }
  if(conxn[nr].inbuf_tail > conxn[nr].inbuf_head)
  {
    conxn[nr].local_window = max_socket_in_len-conxn[nr].inbuf_tail+conxn[nr].inbuf_head;  //调整窗口大小
  }
  else
  {
    conxn[nr].local_window =  conxn[nr].inbuf_head-conxn[nr].inbuf_tail; //调整窗口大小
  }
  if(conxn[nr].local_window ==0) 
  {
//    conxn[nr].local_window =0;
    conxn[nr].flags |= FLG_WIN_ZERO;
  }
}

//****************************************************************************
// 由应用程序调用
//
// 每隔一段时间调用一次,检查各连接是否有需要传送的内容。
// 
// 内容包括:1、要主动发起连接
//           2、要主动结束连接
//           3、要复位连接
//           4、有数据要发送
//           5、有超时传送存在
//
//**************************************************************
void TCP_TICK()
{
  UINT8 i;
  UINT16 TEMP;
  for(i=0;i<MAX_SOCKET_NUM;i++)
  {
    if(conxn[i].state != STATE_CLOSED &&conxn[i].state != STATE_LISTEN)  
	{
	  if(conxn[i].flags & FLG_WIN_ZERO ) //检查上次窗口是否为0,如果是0,则要发送ACK
	  {
	    if(conxn[i].local_window !=0) 
		{   
		  tcp_send(FLG_ACK,20,i); //通知窗口大小
		  conxn[i].flags &= ~FLG_WIN_ZERO;

		}
	  }

	  switch(conxn[i].flags &~FLG_WIN_ZERO)   //这个FLAGS是由上层来置的,
	  {
	    case FLG_SYN:    //发起连接
		    tcp_send(FLG_SYN,28,i); //将MTU通知对方 
			conxn[i].state   = STATE_ACT_SYN_SENT;
		    conxn[i].flags = 0;
		    break;
		case FLG_FIN:   //要结束此连接
		    tcp_send(FLG_FIN|FLG_ACK,20,i); 
			conxn[i].state = STATE_FIN_WAIT_1;
		    conxn[i].flags = 0;
		    break;
		case FLG_RST:   //要复位此连接
		    tcp_send(FLG_RST,20,i); 
			conxn[i].state = STATE_CLOSED;
		    conxn[i].flags = 0;
		    break;
		case FLG_PSH:   //有数据要传送,并且上次传送的一大包数据对方已经全部收到,这个大包是由对方的窗口大小决定的
            
		    if(conxn[i].his_ack == conxn[i].my_sequence)
			{
			  conxn[i].wait_ack_num = 0;
			  if(conxn[i].offset < conxn[i].outbuf_len)
			  {
			    if(conxn[i].state == STATE_ESTABLISHED)
				{
		          TEMP = TCP_data_send(&(conxn[i].outbuf[conxn[i].offset]),conxn[i].outbuf_len-conxn[i].offset,i); //outbuf_len在收到确认后才清0,这是为了重传
			      //conxn[i].timer = TCP_TIMEOUT;	//超时时间5秒,在时钟中断里减,直到0,如果收到了确认,则将TIMER设定为FF,不需要减了
				  conxn[i].offset += TEMP;
				}
			  }
			  else
			  {
			    conxn[i].flags = 0; //表示已经传送完了,并也完全收到了ACK
			    conxn[i].outbuf_len = 0;
			    conxn[i].offset = 0;
			  }
			}
			else //还没有完全收到对方的ACK,此时要检查是否有需要重传的。
			{
			  if(CHECK_RSEND(&conxn[i])) //重传3次就复位该连接
			  {
			    tcp_send(FLG_RST, 20, i);
				Init_cn(&conxn[i]);
			    /*
				conxn[i].flags = 0; //表示已经传送完了,并也完全收到了ACK
			    conxn[i].outbuf_len = 0;
			    conxn[i].offset = 0;
				conxn[i].wait_ack_num = 0;
				conxn[i].state=STATE_CLOSED;//关闭此连接
				*/
			  }
			}


		    break;

		default:   //检查是否有超时存在
		    if(conxn[i].inactivity==0) //这个计数器在每次收到任何来自对方的信息时都更新
			{
			  tcp_send(FLG_RST,20,i); //在inactivity定义的时间内没有收到来自对方的任何反应,即表示此连接已无效
			  conxn[i].state = STATE_CLOSED;
			  conxn[i].flags = 0;
			}

			if((conxn[i].timer==0)&& conxn[i].repeat < 3)  //这个定时器用于当发送的数据包在TIMER时间内没有收到应答,则要重新传输此数据
			{					   //此时有几种可能:1、SYN没收到 2、FIN没收到 3、FIN ACK没收到 4、数据没收到
			   switch(conxn[i].state)
			   {
		          case STATE_ACT_SYN_SENT: //说明是主动发送的SYN没有收到应答,则重新传递
			          {
					  conxn[i].my_sequence = conxn[i].old_sequence; //重串SYN包
					  conxn[i].repeat ++;
					  if(conxn[i].repeat == 4)
					  {
					    printf("repeat syn end\n");
						conxn[i].state = STATE_CLOSED; 
					  }
					  else 
					  {
					    tcp_send(FLG_SYN,28,i);
						printf("r send syn\n");
					  }
			          }
					  break;

			      case STATE_FIN_WAIT_1:  //表示主动发送的FIN没有被收到
				  case STATE_LAST_ACK:	//收到对方的FIN后,发回了FIN ACK可对方没有回答 ,重发FIN ACK
					  conxn[i].my_sequence = conxn[i].old_sequence;
					  conxn[i].repeat ++;
					  if(conxn[i].repeat == 4)
					  {
					    printf("repeat fin end\n");
						conxn[i].state = STATE_CLOSED; 
					  }
					  else 
					  {
					    tcp_send(FLG_FIN|FLG_ACK,20,i);
						printf("r send fin\n");
					  }
					  break;
				  case STATE_ESTABLISHED:  //数据重传,这里不可能到,因为已经在上面处理了一次(CASE FLG_PSH)
				      printf("it is not here\n");
//				      {
//					  conxn[i].my_sequence = conxn[i].old_sequence;
//					  TCP_data_send(conxn[i].outbuf,conxn[i].outbuf_len,i);
//					  conxn[i].my_sequence += conxn[i].outbuf_len;
//					  }
				      break;
				  default:
				      printf("it is error\n");

				      break;
			   }
			   conxn[i].repeat++;
			   if(conxn[i].repeat==3) //重传3次
			   {
                 printf("repeat end\n");
			     conxn[i].state = STATE_CLOSED; //关闭连接。
				 conxn[i].repeat = 0;
			   }
			}

		    break;

	  }

	}
  }
}
//***************************************************************
//传送1包TCP数据

void tcp_send_1_packet(UINT8  *buf, UINT16 len, UINT8 nr)
{
   TCPLAYER  xdata * tcp;
   struct pseudotcp    *TCP_chk;
   UINT8 *outbuf;

   outbuf = (UINT8 *)&IP_IN;  //作为数据的唯一的传输通道
   memcp(outbuf+40,buf,len);
   // Fill in TCP segment header
   tcp = (TCPLAYER *)(outbuf + 20);
   TCP_chk = (struct pseudotcp  *)(outbuf +8);
	
   tcp->tcp_src = conxn[nr].local_port; //PORT;
   tcp->tcp_dest = conxn[nr].port;
   tcp->tcp_seq = conxn[nr].my_sequence;
   tcp->tcp_ack = conxn[nr].his_sequence;
	// Header is always 20 bytes long
   tcp->flags = 0x5000 | FLG_ACK | FLG_PSH;
   tcp->tcp_window = conxn[nr].local_window;
   tcp->tcp_check = 0;
   tcp->tcp_urgent = 0;
   
   // Compute checksum including 12 bytes of pseudoheader
	// Must pre-fill 2 items in ip header to do this
	memcp(TCP_chk->source, conxn[nr].ipaddr,4);
	memcp(TCP_chk->dest,MY_IP,4);
	TCP_chk->z = 0;
	TCP_chk->proto = 6;
	TCP_chk->tcplen = 20+len;
	
	// Sum source_ipaddr, dest_ipaddr, and entire TCP message 
	tcp->tcp_check = ~Check_sum(outbuf + 8, 32 + len);
//	tcp->tcp_check = 0;

	IP_Send(&outbuf[20], len+20, conxn[nr].ipaddr, IP_TCP_PROT, 120);
    
	memcp((UINT8 *)&conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].TCP_HEAD,&outbuf[20],20); //存放的是TCP包头
    conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].Repeat = 0;
	conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].Timer = TCP_TIMEOUT;
	conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].START_PTR = buf;
	conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].LENGTH = len;
	conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].State  = 1; //wait for ack
	conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].expect_ack = conxn[nr].my_sequence+len; //期待受到的ACK
	conxn[nr].tcp_wait_ack[conxn[nr].wait_ack_num].R_ACK_NUM = 0;
	conxn[nr].wait_ack_num++;

	if(conxn[nr].wait_ack_num == max_tcp_wait_num)  //等待ACK的TCP包超过设定的极限时,将只保留最后一个
	{
	  printf("tcp wait ack full\n");
	  conxn[nr].wait_ack_num--;
	}
}
//****************************************************************************************************
// 检查是否有需要重传的TCP包,如果有则重新传送那一包
// 重传的条件一个是对方不停回答同一个ACK超过3次,另一个是超时TCP_TIMEOUT
// 重传3次后就复位此连接。
// 返回:0表示不复位此连接 1是复位
UINT8 CHECK_RSEND(CONNECTION *CN)
{
  UINT8 i;
  UINT8 *outbuf;
  struct pseudotcp    *TCP_chk;

  outbuf = (UINT8 *)&IP_IN;

  if(CN->wait_ack_num ==0) return 0;
  if(CN->S_R_ACK_NUM ==0)  return 0; //没有需要重传的包,表示在
  for(i=0;i<CN->wait_ack_num;i++)
  {
    if((CN->tcp_wait_ack[i].R_ACK_NUM ==3)||(CN->tcp_wait_ack[i].Timer ==0)) //找需要重传的数据包,这是由对方的不停的回同一个ACK或超时造成的
	{
	  CN->tcp_wait_ack[i].TCP_HEAD.tcp_ack = CN->his_sequence; //要将我方的ACK变为最新的送回去 
      CN->tcp_wait_ack[i].TCP_HEAD.tcp_window = CN->local_window;
 	  CN->tcp_wait_ack[i].TCP_HEAD.tcp_check = 0;
	  memcp(outbuf+20,(UINT8 *)&CN->tcp_wait_ack[i].TCP_HEAD,20); //先把TCP头拷贝过去,再拷贝数据
	  memcp(outbuf+40,CN->tcp_wait_ack[i].START_PTR,CN->tcp_wait_ack[i].LENGTH); //tcp data

	  TCP_chk = (struct pseudotcp *)(outbuf +8); //
	  memcp(TCP_chk->source, CN->ipaddr,4);
	  memcp(TCP_chk->dest,MY_IP,4);
	  TCP_chk->z = 0;
	  TCP_chk->proto = 6;
	  TCP_chk->tcplen = 20+CN->tcp_wait_ack[i].LENGTH;

	  CN->tcp_wait_ack[i].TCP_HEAD.tcp_check = ~Check_sum(outbuf + 8, 32 + CN->tcp_wait_ack[i].LENGTH);
	  memcp(outbuf+20,(UINT8 *)&CN->tcp_wait_ack[i].TCP_HEAD,20);
  

	  IP_Send(&outbuf[20], CN->tcp_wait_ack[i].LENGTH+20, CN->ipaddr, IP_TCP_PROT, 120); 
	  CN->tcp_wait_ack[i].R_ACK_NUM = 0;  //本包数据重传次数计数
	  CN->tcp_wait_ack[i].Timer = TCP_TIMEOUT;
      CN->tcp_wait_ack[i].Repeat++;
	  if(CN->tcp_wait_ack[i].Repeat>3)
	  {
	    printf("repeat 3\n");
	    CN->repeat = 3;  //重传次数超过了3次。应复位对方
		return 1;
	  }
	}
  }
  return 0;
}

//***********************************************************************
// 这个函数要在主程序的时钟中断里每隔0.5S调用一次,就是对SOCKET级的Timer和inactivity,以及在SOCKET的
// tcp_wait_ack中的timer做减一操作,而在TCP_TICK中处理重传问题

// 这样可以减少中断处理的开销

//***********************************************************************

void tcp_timer_scan()
{
   UINT8 nr,i;
   // Scan through all active connections 
   for (nr = 0; nr < MAX_SOCKET_NUM; nr++)
   {
      if ((conxn[nr].state != STATE_CLOSED) && (conxn[nr].state != STATE_LISTEN))//这两种状态都是原始态肯定没有超时
      {
	     if (conxn[nr].timer)  conxn[nr].timer--;
		 if (conxn[nr].inactivity)  conxn[nr].inactivity--;
		 
		 if(conxn[nr].state==STATE_ESTABLISHED && conxn[nr].flags == FLG_PSH)//说明是在数据传输过程中
		 {
		   for(i=0;i<conxn[nr].wait_ack_num;i++) //遍历所有的存储包
		   {
		     if(conxn[nr].tcp_wait_ack[i].State ==1) //只查没有收到ACK的包
			 {
			   if(conxn[nr].tcp_wait_ack[i].Timer!=0) conxn[nr].tcp_wait_ack[i].Timer--;
			 }
		   }
		 }
	  }
   } //end for
}
//******************************************
// 对一个连接清零
void Init_cn( CONNECTION * CN)
{
  UINT16 TT;
  TT = CN->local_port;
  memset((UINT8 *)CN, 0, sizeof(CONNECTION));
  CN->local_port = TT; //
  

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -