首页程序设计STM32程序UIP1.0实现UDP通讯--方法1

UIP1.0实现UDP通讯--方法1

时间2016-03-30 10:26:50发布caterwang分类STM32程序浏览4067

    针对uip1.0中UDP通讯功能实现方法的描述,这里的方法只能被动接收,然后回应.

    在基于STM32+ENC28J60的硬件平台上调试UIP协议有一短时间了,TCP/IP的客户端及服务端都调通了--只需要按照正点原子或是野火的示例代码配置即可成功,但是关于UDP通讯部分大家都讲得不多,网上也部分人讲过,但是自己还是不怎么明白。

    于是自己的就专门就以太网帧格式这个点调试UDP通讯。目的是要实现UPD广播通讯,这里不先不讲如何从代码上实现的,先来看看一个完整的以太网帧格式是什么样子的。正常情况下,我们的板子收到的都是IP包,所以就以此展开说明。

    1.IP包报文结构---下图为一个标准的IP包报文结构

IP.jpg

    2.以太网帧头部

    包含:目的MAC地址+源MAC地址+协议类型(作用是标识高层协议)

    实测发现板收到数据都是:以太网帧头部 + IP包报文,但是板回复时很多信息都变为了0,规结起来就是这个包不知道要发给谁,即使知道要发给谁,这些信息都是指向我们的网关路由器,连报文的类型都由0x800,变成了0x806。

    查阅了很多网友的经验,再研究了UIP的代码才发现,UIP的UDP通讯不管是广播还是单播,都是基于已连接的基础上的,也就是说进行UDP通讯,我们得先知道源端的信息。以下为UIP输入端的源码(uip.c中 udp_input:标号位置):

  i=0;
  for(uip_udp_conn = &uip_udp_conns[0];
      uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
      ++uip_udp_conn) {
    /* If the local UDP port is non-zero, the connection is considered
       to be used. If so, the local port number is checked against the
       destination port number in the received packet. If the two port
       numbers match, the remote port number is checked if the
       connection is bound to a remote port. Finally, if the
       connection is bound to a remote IP address, the source IP
       address of the packet is checked. */
		i++;
    if(uip_udp_conn->lport != 0 &&
       UDPBUF->destport == uip_udp_conn->lport &&
       (uip_udp_conn->rport == 0 ||
        UDPBUF->srcport == uip_udp_conn->rport) &&
       (uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) ||
	      uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) ||
	      uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
      goto udp_found;
    }

    于是为了达到以下功能:收到UPD包时,只对比目的端口,目的IP,并备份源端口及IP。改写了这部分代码,

if(UDPBUF->destport == uip_udp_conn->lport &&						         
  (uip_ipaddr_cmp(BUF->destipaddr, all_zeroes_addr) ||		      
   uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr)   ||		      
   uip_ipaddr_cmp(BUF->destipaddr,uip_udp_conn->lipaddr)))
		{
			uip_udp_conn->rport = UDPBUF->srcport;
			uip_ipaddr_copy(uip_udp_conn->ripaddr,BUF->srcipaddr);	
			goto udp_found;
		}


为了配合以上代码的实现,还要对uip_udp_new()函数进行改写,改写后如下:

struct uip_udp_conn *
uip_udp_new(uip_ipaddr_t *ripaddr, u16_t lport)
{
  register struct uip_udp_conn *conn;
	for(c = 0; c < UIP_UDP_CONNS; ++c)
		{
			uip_ipaddr_copy(uip_udp_conns[c].lipaddr, ripaddr);
			uip_udp_conns[c].lport = lport;
			uip_udp_conns[c].rport = 0;
			uip_udp_conns[c].ttl = UIP_TTL;
		}
  return conn;
}

其中参数ripaddr,是板子的本地IP,lport是本地监听的端口,这与原码出入有点大。这样改了以后,初始化UDP通讯部分就比较简单明了。如下:

    uip_ipaddr(&ipaddr, ucLocAddr[0],ucLocAddr[1],ucLocAddr[2],ucLocAddr[3]);	
    uip_udp_new(&ipaddr,HTONS(uiUIP_UDP_PORT));

    

    当然了,我们也可以不改后面这个函数只改udp_input部分的代码,只需再定义几个全局变量,并在初始化时初始化好就可以了。

    按以后改动以后,UDP通讯正常,测试了点对点及广播通讯,完全实现我想要的功能。

    以下为测试截图:

blob.png

blob.png

凯特网版权声明:以上内容允许转载,但请注明出处,谢谢!

展开全文READ MORE
STM32UIPUDPENC28J60
ARP协议的报文格式解析 ENC28J60不工作,指示灯常亮的原因

游客 回复需填写必要信息