搜索
bottom↓
回复: 42

AVRNET 学习笔记UDP部分

  [复制链接]

出0入0汤圆

发表于 2013-2-14 22:11:41 | 显示全部楼层 |阅读模式
本帖最后由 xukai871105 于 2013-2-14 22:16 编辑

1前言
        UDP协议全称为用户数据协议,是一种简单有效的运输协议。和以太网首部和IP首部相似,UDP首部也有自身的数据结构定义。从运输协议开始引入端口的概念,端口相当于一个应用程序的标识符。相对于TCP协议而言,UDP协议简单的多。本文将实现UDP协议,并通过几个简单的案例说明UDP的使用。
1.2 相关资料
ENC28J60学习笔记链接
http://www.amobbs.com/thread-5519381-1-1.html
AVRNET学习笔记 ETHERNET和ARP部分
http://www.amobbs.com/thread-5519452-1-1.html
AVRNET学习笔记 IP和ICMP部分
http://www.amobbs.com/thread-5519494-1-1.html
AVRNET项目(国外)
http://www.avrportal.com/?page=avrnet
AVR webserver项目(国外)
http://www.tuxgraphics.org/electronics/200611/article06111.shtml#0lfindex0
2 UDP部分实现
        UDP功能的实现可分为UDP首部填充,UDP缓冲区填充和UDP报文查询。UDP首部填充是一个按部就班的过程,即填充源端口,目标端口,长度和校验和。UDP缓冲区填充即往UDP负载部分逐个填充数据。UDP报文查询功能即匹配本机UDP端口号,并进行函数处理。为了实现这些功能,首先需要以下宏定义。需要注意的是以太网传输协议中数据被以大端的形式保存,即低地址存放了高字节。例如端口号的高字节存放在了0x22的位置,而端口号的低字节存放在了0x23的位置。
  1. // UDP默认端口号
  2. #define UDP_AVR_PORT_V    3000
  3. #define UDP_AVR_PORT_H_V  (UDP_AVR_PORT_V>>8)
  4. #define UDP_AVR_PORT_L_V  (UDP_AVR_PORT_V&0xff)
  5. // 源端口
  6. #define UDP_SRC_PORT_H_P  0x22      
  7. #define UDP_SRC_PORT_L_P  0x23
  8. // 目标端口
  9. #define UDP_DST_PORT_H_P  0x24
  10. #define UDP_DST_PORT_L_P  0x25
  11. // UDP负载长度
  12. #define UDP_LENGTH_H_P    0x26
  13. #define UDP_LENGTH_L_P    0x27
  14. // UDP校验和
  15. #define UDP_CHECKSUM_H_P  0x28
  16. #define UDP_CHECKSUM_L_P  0x29
  17. // UDP负载起始地址
  18. #define UDP_DATA_P        0x2A
复制代码
2.1 UDP首部填充
        UDP首部填充中需要明确UDP的端口号,AVRNET项目中通过常数宏定义实现
#define UDP_AVR_PORT_V    3000
#define UDP_AVR_PORT_H_V  (UDP_AVR_PORT_V>>8)
#define UDP_AVR_PORT_L_V  (UDP_AVR_PORT_V&0xff)
从这段代码中可以看出,AVRNET的UDP端口号为3000。
  1. void udp_generate_header ( BYTE *rxtx_buffer, WORD_BYTES dest_port, WORD_BYTES length )
  2. {
  3.   WORD_BYTES ck;

  4.   // 默认端口号 3000
  5.   rxtx_buffer[UDP_SRC_PORT_H_P] = UDP_AVR_PORT_H_V;
  6.   rxtx_buffer[UDP_SRC_PORT_L_P] = UDP_AVR_PORT_L_V;

  7.   // 目标端口地址
  8.   rxtx_buffer[UDP_DST_PORT_H_P] = dest_port.byte.high;
  9.   rxtx_buffer[UDP_DST_PORT_L_P] = dest_port.byte.low;

  10.   // 负载长度
  11.   rxtx_buffer[UDP_LENGTH_H_P] = length.byte.high;
  12.   rxtx_buffer[UDP_LENGTH_L_P] = length.byte.low;

  13.   // 计算校验和
  14.   rxtx_buffer[UDP_CHECKSUM_H_P] = 0;
  15.   rxtx_buffer[UDP_CHECKSUM_L_P] = 0;
  16.   // length+8 for source/destination IP address length (8-bytes)
  17.   ck.word = software_checksum ( (BYTE*)&rxtx_buffer[IP_SRC_IP_P], length.word+8, length.word+IP_PROTO_UDP_V);
  18.   rxtx_buffer[UDP_CHECKSUM_H_P] = ck.byte.high;
  19.   rxtx_buffer[UDP_CHECKSUM_L_P] = ck.byte.low;
  20. }
复制代码
2.2 UDP负载长度查询
        UDP首部中包含UDP长度的描述字节,长度占有两个字节并以大端格式保存,由于宏定义的提示作用,弱化了大端格式的影响。长度中也包括了UDP首部的长度,UDP首部的长度为固定的8字节。
  1. WORD udp_get_dlength( BYTE *rxtx_buffer )
  2. {
  3.   WORD length = 0;
  4.   // 获得UDP长度
  5.   length = rxtx_buffer[UDP_LENGTH_H_P] << 8 | rxtx_buffer[UDP_LENGTH_L_P];
  6.   // 去除首部长度
  7.   length = length - 8;
  8.   
  9.   return length;
  10. }
复制代码
2.3 UDP负载区填充
        UDP负载去填充即在UDP首部之后填充有用的数据。在这段真实负载之前包括了UDP首部,IP首部和以太网首部,分别占用了8字节,20字节和14字节。UDP负载的起始地址通过宏由UDP_DATA_P定义。对于AVR单片机的特点,为了尽一切可能节约内存使用率,在向负载区填充数据时用到了两个函数,udp_puts_data函数操作的是BYTE*类型的数据,而udp_puts_data_p操作的为PGM_P类型数据,即位于FLASH中的数据,需要通过pgm_read_byte取出。而其他类型的CPU,例如STM却没有该功能,则使用udp_puts_data即可。
  1. WORD udp_puts_data ( BYTE *rxtx_buffer, BYTE *data, WORD offset )
  2. {
  3.   while( *data )
  4.   {
  5.     rxtx_buffer[ UDP_DATA_P + offset ] = *data++;
  6.     offset++;
  7.   }

  8.   return offset;
  9. }
  10. WORD udp_puts_data_p ( BYTE *rxtx_buffer, PGM_P data, WORD offset )
  11. {
  12.   BYTE ch;
  13.   
  14.   while( (ch = pgm_read_byte(data++)) )
  15.   {
  16.     rxtx_buffer[ UDP_DATA_P + offset ] = ch;
  17.     offset++;
  18.   }

  19.   return offset;
  20. }
复制代码
2.4 UDP报文查询
        UDP报文的查询需要匹配接收数据包中的UDP端口号,若匹配成功则可对输入数据包进行处理,这些处理包括解析数据包的数据格式,分析出控制命令或查询命令。也可以通过udp_puts_data向发送缓冲区中填写响应数据。接着逐步生成以太网首部,IP首部和UDP首部,以太网首部中包含目标MAC地址,IP首部中包含目标IP地址,UDP首部中包含目标端口号。
  1. BYTE udp_receive ( BYTE *rxtx_buffer, BYTE *dest_mac, BYTE *dest_ip )
  2. {
  3.   WORD dlength = 0;
  4.   // udp负载长度
  5.   WORD udp_loadlen = 0;

  6.   // 匹配UDP协议 UDP端口号
  7.   if ( rxtx_buffer[IP_PROTO_P] != IP_PROTO_UDP_V || rxtx_buffer[UDP_DST_PORT_H_P] != UDP_AVR_PORT_H_V || rxtx_buffer[ UDP_DST_PORT_L_P ] != UDP_AVR_PORT_L_V )
  8.     return 0;
  9.    
  10. // 加入处理函数

  11.   // 生成以太网首部
  12.   eth_generate_header (rxtx_buffer, (WORD_BYTES){ETH_TYPE_IP_V}, dest_mac );
  13.   // 生成IP首部
  14.   ip_generate_header (rxtx_buffer, (WORD_BYTES){sizeof(IP_HEADER)+sizeof(UDP_HEADER)+dlength}, IP_PROTO_UDP_V, dest_ip );
  15.   // 生成UDP首部
  16.   udp_generate_header (rxtx_buffer, (WORD_BYTES){(rxtx_buffer[UDP_SRC_PORT_H_P]<<8)|rxtx_buffer[UDP_SRC_PORT_L_P]}, (WORD_BYTES){sizeof(UDP_HEADER)+dlength});
  17.   // 发送所有首部和UDP负载数据
  18.   enc28j60_packet_send ( rxtx_buffer, sizeof(ETH_HEADER)+sizeof(IP_HEADER)+sizeof(UDP_HEADER)+dlength );

  19.   return 1;
  20. }
复制代码
3 实验
        实验部分主要是为了验证UDP协议,通过PC机上的网络调试软件开辟一个PC机的UDP端口,假定端口号为3001,IP地址为192.168.1.102;AVR的UDP默认端口号为3000,IP地址为192.168.1.105。
3.1 程序结构
        在运行UDP程序之前,需要运行ARP,IP和ICMP各部分,并保存发起发的MAC地址和IP地址。
  1. /* 获得新的IP报文 */
  2.   plen = enc28j60_packet_receive( (BYTE*)&rxtx_buffer, MAX_RXTX_BUFFER );
  3.   if(plen==0) return;

  4.   /* 保存客服端的MAC地址 */
  5.   memcpy ( (BYTE*)&client_mac, &rxtx_buffer[ ETH_SRC_MAC_P ], sizeof(MAC_ADDR) );
  6.   /* 检查该报文是不是ARP报文 */
  7.   if ( arp_packet_is_arp( rxtx_buffer, (WORD_BYTES){ARP_OPCODE_REQUEST_V} ) )
  8.   {
  9.     /* 向客户端返回ARP报文 */
  10.     arp_send_reply ( (BYTE*)&rxtx_buffer, (BYTE*)&client_mac );
  11.     return;
  12.   }

  13.   /* 保存客服端的IP地址 */
  14.   memcpy ( (BYTE*)&client_ip, &rxtx_buffer[ IP_SRC_IP_P ], sizeof(IP_ADDR) );  
  15.   /* 检查该报文是否为IP报文 */
  16.   if ( ip_packet_is_ip ( (BYTE*)&rxtx_buffer ) == 0 )
  17.   {
  18.     return;
  19.   }
  20.   
  21.   /* 如果是ICMP报文 向发起方返回数据 */
  22.   if ( icmp_send_reply ( (BYTE*)&rxtx_buffer, (BYTE*)&client_mac, (BYTE*)&client_ip ) )
  23.   {
  24.     return;
  25.   }
  26.   
  27.   // 进行UDP处理
  28.         if (udp_receive ( (BYTE *)&rxtx_buffer, (BYTE *)&client_mac, (BYTE *)&client_ip ))
  29.         {
  30.           return;
  31.         }
复制代码
3.2 源IP和源端口
        使用网路调试助手发送一个名称,例如UDP。在仿真环境中通过串口打印出发起方的IP地址和端口号,例如PC机的端口号设定为3001,PC机的IP地址为192.168.1.102。在udp_receive函数中需要判断UDP端口号和目标IP地址是否匹配,若匹配即可加入以下代码。首先获得UDP的负载长度,使用memcpy命令复制到udp_recbuf中,接着通过串口打印源IP地址,该参数位于IP首部,源端口号,该参数位于UDP首部中。
  1. // 获得UDP负载长度
  2.     udp_loadlen = udp_get_dlength(rxtx_buffer);
  3.    
  4.     // 复制UDP负载
  5.     memcpy(udp_recbuf,(char*)&rxtx_buffer[UDP_DATA_P],udp_loadlen);
  6.   
  7.   #ifdef UDP_DEBUG
  8.     printf("UDP Message!\n");
  9.     printf("Send Form:%d.%d.%d.%d ",\
  10.           rxtx_buffer[IP_SRC_IP_P+0],rxtx_buffer[IP_SRC_IP_P+1],\
  11.           rxtx_buffer[IP_SRC_IP_P+2],rxtx_buffer[IP_SRC_IP_P+3]);
  12.     printf("Port:%d\n",(rxtx_buffer[UDP_SRC_PORT_H_P] << 8) | rxtx_buffer[UDP_SRC_PORT_L_P]);
  13.     printf("Reccive:%s\n",udp_recbuf);
  14.   #endif
复制代码

图 网络调试助手

网络调试助手使用时,先设定协议类型为UDP,并修改本机端口号改为3000,点击连接。然后修改目标主机的IP地址,改为AVR的IP地址,目标端口号改为3000.最后填入数据点击发送。

图 UDP 输出结果

可以看出,PC机先发送UDP命令之前先发送了一个ARP请求,找出AVR的MAC地址,接着发送UDP数据包。这个实验可以验证UDP接收数据包正确。
3.3 返回Hello UDP
        接着稍微修改一下上面的程序,接收到UDP数据包之后,在负载数据之前加入Hello字符,如果输入的为xukai871105,则返回Hello xukai871105。可以通过网络调试助手看到返回的结果。使用strcpy函数把Hello复制到udp_sendbuf数组中,接着使用strcat把udp_recbuf中的字符串连接到udp_sendbuf之后,最后调用udp_puts_date填充到发送缓冲区中,udp_puts_date的最后一个参数为缓冲区的起始字节,第一次填入时应使用0。
  1. // 获得UDP负载长度
  2.     udp_loadlen = udp_get_dlength(rxtx_buffer);
  3.    
  4.     // 复制UDP负载
  5.     memcpy(udp_recbuf,(char*)&rxtx_buffer[UDP_DATA_P],udp_loadlen);
  6.   
  7.   #ifdef UDP_DEBUG
  8.     printf("UDP Message!\n");
  9.     printf("Send Form:%d.%d.%d.%d ",\
  10.           rxtx_buffer[IP_SRC_IP_P+0],rxtx_buffer[IP_SRC_IP_P+1],\
  11.           rxtx_buffer[IP_SRC_IP_P+2],rxtx_buffer[IP_SRC_IP_P+3]);
  12.     printf("Port:%d\n",(rxtx_buffer[UDP_SRC_PORT_H_P] << 8) | rxtx_buffer[UDP_SRC_PORT_L_P]);
  13.     printf("Reccive:%s\n",udp_recbuf);
  14.   #endif
  15.    
  16.     // 复制Hello
  17.     strcpy(udp_sendbuf,"Hello ");
  18.     // 连接数据
  19.     strcat(udp_sendbuf,udp_recbuf);
  20. dlength = udp_puts_data ( rxtx_buffer,(BYTE*)udp_sendbuf, 0 );
复制代码

图 UDP返回结果

        通过前面两个实验可以证明UDP的接收和发送工作正常。
3.4 LED控制
        验证了UDP的发送和接收,可以通过定义一组指令实现LED的控制。AVRNET项目中有两个LED指示灯,设计这样一组指令打开或关闭LED,例如
led1=1                打开LED1
led1=0                关闭LED1
led2=1                打开LED2
led2=0               关闭LED2
具体代码如下。通过memcmp比较UDP数据包的中前4个字符是否为led1,如果两个字符串相等,则进行led1的控制处理,在根据第5个字节(从0开始)判断操作是打开还是关闭。
  1.    // 获得UDP负载长度
  2.     udp_loadlen = udp_get_dlength(rxtx_buffer);
  3.    
  4.     // 复制UDP负载
  5.     memcpy(udp_recbuf,(char*)&rxtx_buffer[UDP_DATA_P],udp_loadlen);
  6.   
  7.   #ifdef UDP_DEBUG
  8.     printf("UDP Message!\n");
  9.     printf("Send Form:%d.%d.%d.%d ",\
  10.           rxtx_buffer[IP_SRC_IP_P+0],rxtx_buffer[IP_SRC_IP_P+1],\
  11.           rxtx_buffer[IP_SRC_IP_P+2],rxtx_buffer[IP_SRC_IP_P+3]);
  12.     printf("Port:%d\n",(rxtx_buffer[UDP_SRC_PORT_H_P] << 8) | rxtx_buffer[UDP_SRC_PORT_L_P]);
  13.     printf("Reccive:%s\n",udp_recbuf);
  14.   #endif
  15.    
  16.     // 命令解析  led1=1
  17.     if( !memcmp((char*)&udp_recbuf,"led1",4) )
  18.     {
  19.       // led1 = 1
  20.       if( udp_recbuf[5] == '1')
  21.       {
  22.         LED_PORT &= ~_BV ( LED_PIN1 );
  23.       }
  24.       else
  25.       {
  26.         LED_PORT |= _BV( LED_PIN1 );
  27.       }
  28.       dlength = udp_puts_data_p ( rxtx_buffer, PSTR("led1 command"), 0 );
  29. }
复制代码

图 通过led=1命令控制LED点亮

4总结
        UDP是一个非常简答有效的协议。协议占用的Flash和RAM的空间较小,LED控制实例调试时占用的RAM空间为409字节,仅占用了AVRNET使用的ATmega32内存空间的20%。研究完UDP协议之后便可研究分析TCP协议,在熟悉的TCP协议的基础上才可实践HTTP制作WEB网页。使用嵌入式实践WEB服务器之前还需要练习静态网页动态网页的制作方法,熟悉HTTP请求格式等等工作。
最后附上工程代码!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2013-2-15 00:03:12 | 显示全部楼层
好人,高手,必须顶!

出0入0汤圆

 楼主| 发表于 2013-2-15 13:50:54 | 显示全部楼层
xslff 发表于 2013-2-15 00:03
好人,高手,必须顶!

只要有人顶,就继续写!下一个TCP!

出0入0汤圆

发表于 2013-2-15 13:51:50 | 显示全部楼层
楼主的帖子很全,努力研读

出0入0汤圆

发表于 2013-2-17 18:09:26 | 显示全部楼层
学习了   ----

出0入0汤圆

发表于 2013-4-4 11:09:20 | 显示全部楼层
顶楼主,向楼主学习

出0入0汤圆

发表于 2013-7-8 17:51:34 | 显示全部楼层
我想请问下 伪首部 好像没有看到 UDP校验不是要加伪首部吗  下面贴上老外的那个校验函数  我感觉似乎有伪首部 但是感觉 不是很明白

出0入0汤圆

发表于 2013-7-8 17:51:49 | 显示全部楼层
uint16_t checksum(uint8_t *buf, uint16_t len,uint8_t type){
        // type 0=ip
        //      1=udp
        //      2=tcp
        uint32_t sum = 0;

        //if(type==0){
        //        // do not add anything
        //}
        if(type==1){
                sum+=IP_PROTO_UDP_V; // protocol udp
                // the length here is the length of udp (data+header len)
                // =length given to this function - (IP.scr+IP.dst length)
                sum+=len-8; // = real tcp len
        }
        if(type==2){
                sum+=IP_PROTO_TCP_V;
                // the length here is the length of tcp (data+header len)
                // =length given to this function - (IP.scr+IP.dst length)
                sum+=len-8; // = real tcp len
        }
        // build the sum of 16bit words
        while(len >1){
                sum += 0xFFFF & (((uint32_t)*buf<<8)|*(buf+1));
                buf+=2;
                len-=2;
        }
        // if there is a byte left then add it (padded with zero)
        if (len){
                sum += ((uint32_t)(0xFF & *buf))<<8;
        }
        // now calculate the sum over the bytes in the sum
        // until the result is only 16bit long
        while (sum>>16){
                sum = (sum & 0xFFFF)+(sum >> 16);
        }
        // build 1's complement:
        return( (uint16_t) sum ^ 0xFFFF);
}

出0入0汤圆

 楼主| 发表于 2013-7-8 20:56:49 | 显示全部楼层
wujin 发表于 2013-7-8 17:51
uint16_t checksum(uint8_t *buf, uint16_t len,uint8_t type){
        // type 0=ip
        //      1= ...

和校验的部分我并没有深究!以后有机会还是要详细看看的!

出0入0汤圆

发表于 2013-7-8 22:57:15 | 显示全部楼层
我也来顶一个,楼主继续写啊

出0入0汤圆

发表于 2013-7-9 11:36:56 | 显示全部楼层
xukai871105 发表于 2013-7-8 20:56
和校验的部分我并没有深究!以后有机会还是要详细看看的!

sum+=IP_PROTO_UDP_V; // protocol udp
                // the length here is the length of udp (data+header len)
                // =length given to this function - (IP.scr+IP.dst length)
                sum+=len-8; // = real tcp len
应该是加进了伪首部 这个 ip选项是没有的 前面是源地址 目的地址 加上 协议udp 17 加长度  

出0入0汤圆

 楼主| 发表于 2013-7-9 20:16:04 | 显示全部楼层
ranjiexu 发表于 2013-7-8 22:57
我也来顶一个,楼主继续写啊

点我头像下面的主题数自然可以看到了!

出0入0汤圆

发表于 2013-7-12 15:56:04 | 显示全部楼层
xukai871105 发表于 2013-7-9 20:16
点我头像下面的主题数自然可以看到了!

楼主 我把压缩包的程序下载回去后,发现通信不了,我用内振8M的,,用电脑ping和用一些udp发送的软件调试过,发觉老是没有收到IP包,IP地址和端口都正确的,求助

出0入0汤圆

 楼主| 发表于 2013-7-12 16:22:17 | 显示全部楼层
wweiboou 发表于 2013-7-12 15:56
楼主 我把压缩包的程序下载回去后,发现通信不了,我用内振8M的,,用电脑ping和用一些udp发送的软件调试 ...

请问你是在目标板上运行的吗?由于我没有AVR的设备,所以我只能仿真调试了!
请问,SPI端口等和硬件有关的设置调整了吗!

出0入0汤圆

发表于 2013-7-12 16:41:34 | 显示全部楼层
xukai871105 发表于 2013-7-12 16:22
请问你是在目标板上运行的吗?由于我没有AVR的设备,所以我只能仿真调试了!
请问,SPI端口等和硬件有关 ...

感谢你的回复  我硬件上面的SPI接口已经按照程序上面接了

出0入0汤圆

发表于 2013-7-12 17:11:26 | 显示全部楼层
wweiboou 发表于 2013-7-12 16:41
感谢你的回复  我硬件上面的SPI接口已经按照程序上面接了

漏了说, 但还是不行的 求助求助楼主

出0入0汤圆

 楼主| 发表于 2013-7-12 21:08:39 | 显示全部楼层
wweiboou 发表于 2013-7-12 17:11
漏了说, 但还是不行的 求助求助楼主

你能把调试环境描述的更清楚一些吗!
例如本地IP地址,ENC28J60供电情况等,越清楚越好!

出0入0汤圆

发表于 2013-8-15 17:22:10 | 显示全部楼层
WORD udp_get_dlength( BYTE *rxtx_buffer )
{
  WORD length = 0;
  // 获得UDP长度
  length = rxtx_buffer[UDP_LENGTH_H_P] << 8 | rxtx_buffer[UDP_LENGTH_L_P];
  // 去除首部长度
  length = length - 8;
  
  return length;
}
修正楼主一个小语法错误, length = rxtx_buffer[UDP_LENGTH_H_P] << 8 | rxtx_buffer[UDP_LENGTH_L_P];应该改成 length = (WORD )rxtx_buffer[UDP_LENGTH_H_P] << 8 | rxtx_buffer[UDP_LENGTH_L_P];  否则如果数据量大于256会出错的。

出0入0汤圆

发表于 2013-8-15 17:22:50 | 显示全部楼层
WORD udp_get_dlength( BYTE *rxtx_buffer )
{
  WORD length = 0;
  // 获得UDP长度
  length = rxtx_buffer[UDP_LENGTH_H_P] << 8 | rxtx_buffer[UDP_LENGTH_L_P];
  // 去除首部长度
  length = length - 8;
  
  return length;
}
修正楼主一个小语法错误, length = rxtx_buffer[UDP_LENGTH_H_P] << 8 | rxtx_buffer[UDP_LENGTH_L_P];应该改成 length = (WORD )rxtx_buffer[UDP_LENGTH_H_P] << 8 | rxtx_buffer[UDP_LENGTH_L_P];  否则如果数据量大于256会出错的。

出0入0汤圆

 楼主| 发表于 2013-8-15 20:06:30 | 显示全部楼层
wolyond 发表于 2013-8-15 17:22
WORD udp_get_dlength( BYTE *rxtx_buffer )
{
  WORD length = 0;

明白,任何细节问题都不能放过!

出0入0汤圆

发表于 2013-8-16 08:35:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-10-5 13:48:45 | 显示全部楼层
我想问下,这句话怎样理解?
if( memcmp((char*)&udp_recbuf,"led1",4)==0 )

出0入0汤圆

 楼主| 发表于 2013-10-5 13:51:38 | 显示全部楼层
enovo2468 发表于 2013-10-5 13:48
我想问下,这句话怎样理解?
if( memcmp((char*)&udp_recbuf,"led1",4)==0 )

比较UDP负载中的数据是不是以 led1开头
你可以查看一下memcmp函数的作用,一看就明白!

出0入0汤圆

发表于 2013-10-5 15:05:13 | 显示全部楼层
xukai871105 发表于 2013-10-5 13:51
比较UDP负载中的数据是不是以 led1开头
你可以查看一下memcmp函数的作用,一看就明白! ...

知道了,比较ascII码值的

出0入0汤圆

发表于 2013-10-5 22:39:50 | 显示全部楼层
算了一晚上,校验和就是不对,唉不算了,能用就OK

出0入0汤圆

发表于 2013-10-6 18:06:05 | 显示全部楼层
校验和算出来了
源IP     目的IP    源端口  目的端口  UDP长度    校验和0x0000      数据  =A

A右移16位 +  A  =B

校验和=B取反

出0入0汤圆

发表于 2013-10-6 18:48:20 | 显示全部楼层
enovo2468 发表于 2013-10-6 18:06
校验和算出来了
源IP     目的IP    源端口  目的端口  UDP长度    校验和0x0000      数据  =A

漏了两个  IP后边还要  +UDP协议 和 UDP长度

出0入0汤圆

发表于 2013-10-12 20:03:55 | 显示全部楼层
先收藏了以后学习,谢谢楼主分享!

出0入0汤圆

发表于 2013-11-13 15:21:57 | 显示全部楼层
终于找到了UDP全面的解释了~谢谢~正在调试UDP,直接看别人的代码有点摸不着头脑~继续关注中

出0入0汤圆

发表于 2013-11-15 14:15:21 | 显示全部楼层
比较好的资料,正在学习中

出0入0汤圆

发表于 2013-12-18 13:03:28 | 显示全部楼层
好人啊  支持一个      

出0入0汤圆

 楼主| 发表于 2013-12-18 22:06:40 | 显示全部楼层
swustlx 发表于 2013-12-18 13:03
好人啊  支持一个

我再接再励!

出0入0汤圆

发表于 2013-12-20 18:41:18 | 显示全部楼层
mark a mark

出0入0汤圆

发表于 2013-12-22 15:18:48 | 显示全部楼层
楼主,你好啊,我是 使用stm32+enc28j60移植uip协议实现以太网功能,我直接使用网线将enc28j60和pc机相连,程序是原子库函数版本的,我把电脑上的ip地址设置为静态的,ip为192.168.1.103,32板的iP设置为192.168.1.16  ,进行ping 192.168.1.16,ping不通,这是为什么呢,还是说要通过路由进行呢

出0入0汤圆

 楼主| 发表于 2013-12-23 12:18:05 | 显示全部楼层
叶子飞翔 发表于 2013-12-22 15:18
楼主,你好啊,我是 使用stm32+enc28j60移植uip协议实现以太网功能,我直接使用网线将enc28j60和pc机相连, ...

你好,本周六的时候我还测试了这个代码和PC机直连,是否可以通信成功,结果是成功的。

我没有使用阅读过原子uIP部分的代码,所以我不能确定你是什么原因导致失败的!

不过我最近遇到过一次ENC28J60硬件损坏的情况!

出0入0汤圆

发表于 2013-12-24 11:46:56 | 显示全部楼层
xukai871105 发表于 2013-12-23 12:18
你好,本周六的时候我还测试了这个代码和PC机直连,是否可以通信成功,结果是成功的。

我没有使用阅读过 ...

谢谢楼主回答,我enc28j60是可以初始化成功的,硬件方面应该是没有问题的。我想问下楼主,你电脑上的ip地址是设置为静态的吗

出0入0汤圆

 楼主| 发表于 2013-12-25 09:22:18 | 显示全部楼层
叶子飞翔 发表于 2013-12-24 11:46
谢谢楼主回答,我enc28j60是可以初始化成功的,硬件方面应该是没有问题的。我想问下楼主,你电脑上的ip地 ...

直连的时候我设置的为静态,接到路由器上的话,DHCP有路由器分配!

出0入0汤圆

发表于 2013-12-25 10:11:01 | 显示全部楼层
xukai871105 发表于 2013-12-25 09:22
直连的时候我设置的为静态,接到路由器上的话,DHCP有路由器分配!

那请问下楼主如果ping不通是程序导致的问题,一般是哪些地方有问题呢,这样我就可以单步调试和在线仿真下看看到底哪里出问题了

出0入0汤圆

发表于 2014-1-10 16:27:28 | 显示全部楼层
MARK, 学习中,谢谢分享

出0入0汤圆

发表于 2014-11-1 16:54:49 | 显示全部楼层
非常好!!!

出0入0汤圆

发表于 2015-2-5 10:27:18 | 显示全部楼层
先看看 UDP的 格式帧 再 看此贴。感谢LZ的贡献~

出0入0汤圆

发表于 2015-2-5 14:08:22 | 显示全部楼层
xukai871105 发表于 2013-2-15 13:50
只要有人顶,就继续写!下一个TCP!

Lz 帮你提供个我 自己画 的图!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2015-10-14 22:46:44 | 显示全部楼层
failed to initialize winpcap drives 仿真时出现这个错误提示什么意思
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 09:33

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表