基于PLC1850平台的UDP报文接收与发送
一、UDP报文格式
源端口(2个字节):发送报文的进程的16位端口号。
目的端口(2个字节):目的设备上的接收进程的16位端口号。
长度(2个字节):整个UDP数据报的长度,包括首都和数据字段。
校验和(2个字节):提供错误检测功能的16位校验和,为可选项。
数据(可变长度):要发送已封存应用报文。
2、UDP封装
3、UDP校验和计算
UDP校验和是所计算字段的16位反码和的反码,用IP数据报的某些字段组成一个伪首部,再与UDP报文合在一起计算校验和。因此,校验和是对伪首部、UDP首部和UDP数据的计算结果。如果需要,数据后面可能会填以数值为0的字节,使得数据字节数为两字节的整数倍。
4、发送UDP报文
通过java语言编写一个UDP数据报发送个LPC1850平台,程序代码如下:
/**
* @Author CFF
* @Date:Created in 22:45 2019/4/20
*/
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress; public class udp {
public static void main(String[] args ) throws Exception {
String content = "ABCDEFGHIJ";
byte [] sentBuf = content .getBytes( "GBK" );
DatagramSocket client = new DatagramSocket();
InetAddress destinationAddress =InetAddress. getByName ( "192.168.1.190" );
int port =2425;
DatagramPacket sendPacket = new DatagramPacket( sentBuf , sentBuf.length , destinationAddress , port );
client .send(sendPacket);
client .close();
}
}
5、LPC1850代码
LPC1850 Internet初始化主函数,代码如下:
#include "LPC18xx.h"
#include "led.h" extern void taskEth (void); int main(void)
{
SystemInit(); ledInit();
SysTick_Config(GetCoreClock() / ); taskEth(); while ();
} void SysTick_Handler(void)
{
static int counter = ; counter++;
if (counter >= )
{
counter = ;
ledRolling();
}
}
EthTask.c代码如下:
#include <stdlib.h>
#include <lpc18xx.h>
#include "lpc18xx_emac.h"
#include "lpc18xx_debug.h" extern uint32_t ipatol(char * p_input);
extern void ipInit(uint8_t * mac, uint32_t ip);
extern uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen); uint8_t gFlag = ; uint8_t g_emacBuffer[]; uint8_t g_ethMac[]; // EMAC½Ó¿Ú½ÓÊÕµ½Êý¾Ý£¬Í¨ÖªÓ¦ÓòãµÄ»Øµ÷º¯Êý¡£
void ethReadReadyCb()
{
gFlag = ;
} void taskEth (void)
{
uint32_t len; g_ethMac[] = 0x11;
g_ethMac[] = 0x1F;
g_ethMac[] = 0xE0;
g_ethMac[] = 0x12;
g_ethMac[] = 0x1E;
g_ethMac[] = 0x0F; debugComInit();
uartPrint("uart init\r\n"); while (ethInit(ethReadReadyCb, g_ethMac) == ); uartPrint("eth init complete\r\n");
// ΪÒÔÌ«Íø½Ó¿ÚÖ¸¶¨MACµØÖ·ºÍIPµØÖ·
ipInit(g_ethMac, 0xBE01A8C0); // 192.168.1.190 while ()
{
if (!gFlag)
{
continue;
} len = ethRead(g_emacBuffer, );
if (len)
{
ipRcvMacFrame((uint8_t *)g_emacBuffer, len);
}
gFlag = ;
}
}
ip.c代码如下:
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "lpc18xx_emac.h"
#include "lpc18xx_debug.h"
//#include "shell.h" #define MAC_TYPE_IP 0x0800 //ipÀàÐÍ
#define MAC_TYPE_ARP 0x0806 //macÀàÐÍ #define ARP_REQ 0x0001 //ARPÇëÇó
#define ARP_RSP 0x0002 //ARPÏìÓ¦ #define ICMP_ECHO_REQUEST 8 // message is an echo request
#define ICMP_ECHO_REPLY 0 // message is an echo reply #define PROT_ICMP 1 // Internet Control Message Protocol
#define PROT_TCP 6 // Transmission Control Protocol
#define PROT_UDP 17 // User Datagram Protocol #define DONT_FRAGMENT 0x4000 //fragment
#define MORE_FRAGMENT 0x2000
#define FRAGMENT_OFFSET 0x1FFF uint8_t * UDPChecksum;
uint8_t g_ethMacAddr[];
uint32_t g_ethIpAddr; uint32_t g_ipSndBuffer[]; uint16_t g_ipIdentifier = ; // ½«×Ö´ÓÖ÷»úÐò×ªÎªÍøÂçÐò
uint16_t htons(uint16_t word)
{
return ((word >> ) & 0x00FF) | ((word << ) & 0xFF00);
} // ½«×Ö´ÓÍøÂçÐòתΪÖ÷»úÐò
uint16_t ntohs(uint16_t word)
{
return ((word >> ) & 0x00FF) | ((word << ) & 0xFF00);
} uint16_t calcChecksum(uint16_t * buffer, uint32_t size)
{
uint32_t cksum; cksum = ; while (size > )
{
cksum += *buffer++;
size -= sizeof(uint16_t);
} if (size)
{
cksum += *(uint8_t*)buffer;
} cksum = (cksum >> ) + (cksum & 0xffff);
cksum += (cksum >>); return (uint16_t)(~cksum);
} // ·¢ËÍARPÏìÓ¦
void arpSndRsp(uint32_t dstIp, uint8_t * mac)
{
uint8_t * block;
//uint32_t blockLen; block = (uint8_t *)g_ipSndBuffer; memcpy(block, mac, ); memcpy(block + , g_ethMacAddr, ); // arp type
*(uint16_t *)&block[] = htons(MAC_TYPE_ARP); // --------- ARP ²ã // Hardway type : Ethernet
block[] = 0x00;
block[] = 0x01; // ip type
*(uint16_t *)&block[] = htons(MAC_TYPE_IP); // Hardway size
block[] = 0x06; // Protocal size
block[] = 0x04; // arp reply
*(uint16_t *)&block[] = htons(ARP_RSP); // Sender MAC address
memcpy(block + , g_ethMacAddr, ); // Sender IP address
*(uint32_t *)&block[] = g_ethIpAddr; // Target MAC address
memcpy(block + , mac, ); // Target IP address : 192.168.0.67
block[] = (uint8_t)dstIp;
block[] = (uint8_t)(dstIp >> );
block[] = (uint8_t)(dstIp >> );
block[] = (uint8_t)(dstIp >> ); // 18¸öÌî³ä×Ö½Ú
memset(block + , , ); ethWrite((uint8_t *)block, );
} void arpRcv(uint8_t * block, uint32_t frameLen)
{
uint32_t srcIp, dstIp;
uint16_t msgType; msgType = ntohs(*(uint16_t *)(block+)); srcIp = (uint32_t)*(uint16_t *)(block + );
srcIp|= ((uint32_t)*(uint16_t *)(block + )) << ; dstIp = (uint32_t)*(uint16_t *)(block + );
dstIp|= ((uint32_t)*(uint16_t *)(block + )) << ; if (dstIp != g_ethIpAddr)
{
return;
} if (msgType == ARP_REQ)
{
arpSndRsp(srcIp, block + );
}
} // ²»¹Ü³É¹¦Óë·ñ,¶¼ÓÉIP²ãÀ´ÊÍ·ÅÊý¾Ý°ü¡£
void ipSnd(uint32_t dstIp, uint8_t * block, uint32_t len, uint8_t protoType, uint8_t * mac)
{
block-= ;
len+= ; // ------------ IP ²ã block[] = 0x45; // IP V4. length 20(5*4) block[] = 0x00; // service *(uint16_t *)&block[] = htons(len); *(uint16_t *)&block[] = htons((uint16_t)g_ipIdentifier++); // identification *(uint16_t *)&block[] = 0x0040; // flag and fragment block[] = ; // TTL block[] = protoType; *(uint16_t *)&block[] = ; // УÑéºÍÏÈÌîÉÏ0 *(uint16_t *)&block[] = (uint16_t)g_ethIpAddr;
*(uint16_t *)&block[] = (uint16_t)(g_ethIpAddr >> ); *(uint16_t *)&block[] = (uint16_t)dstIp;
*(uint16_t *)&block[] = (uint16_t)(dstIp >> ); *(uint16_t *)&block[] = calcChecksum((uint16_t *)block, ); // ------------ MAC ²ã block-= ;
len+= ; memcpy(block, mac , ); memcpy(block + , g_ethMacAddr, ); *(uint16_t *)&block[] = htons(MAC_TYPE_IP); if (len < )
{
// MACÖ¡Ì«¶Ì£¬²¹µ½×î¶Ì³¤¶È¡£
memset(block + len, , - len);
len = ;
} ethWrite((uint8_t *)block, len);
} // ICMPÊÕµ½ÇëÇó£¬ÐèÒª»ØÏìÓ¦¡£
void icmpRcvRequest(uint32_t srcIp, uint8_t * icmp, uint32_t len, uint8_t * mac)
{
uint8_t * block; block = (uint8_t *)g_ipSndBuffer; // Áô³ö 14(MAC)+20(IP)¸ö×Ö½Ú
block+=(+); // ----------- ICMP ²ã
memcpy(block, icmp, len); block[] = ICMP_ECHO_REPLY;
block[] = ; // code *(uint16_t *)&block[] = ; // УÑéºÍÏÈÌîÉÏ0 *(uint16_t *)&block[] = calcChecksum((uint16_t *)block, len); ipSnd(srcIp, (void *)block, len, PROT_ICMP, mac);
}
void udpsend(uint32_t srcIp, uint8_t * udp, uint32_t len, uint8_t * mac)
{
uint8_t * block;
int i;
char sendData[]={'R','e','c','e','i','v','e','.','.','.'};
block = (uint8_t *)g_ipSndBuffer;
// Áô³ö 14(MAC)+20(IP)¸ö×Ö½Ú
block+=(+);
memcpy(block,udp,len); memcpy(block,udp+,);
memcpy(block+,udp,); for(i=;i<;i++)
{
block[+i]=sendData[i];
} *(uint16_t *)&block[] = htons(len); *(uint16_t *)&block[] = ;// УÑéºÍÏÈÌîÉÏ0 *(uint16_t *)&UDPChecksum[]=htons(len);
memcpy(UDPChecksum+,block,len);
*(uint16_t *)&block[] = calcChecksum((uint16_t *)UDPChecksum, len+);
uartPrint("Checksum:0x%04x\r\n",ntohs(*(uint16_t *)&block[]));
ipSnd(srcIp, (void *)block, len, PROT_UDP, mac);
}
//udp½ÓÊÕ
void udpRcv(uint32_t srcIp,uint8_t * udp, uint32_t len, uint8_t * mac)
{
int i;
uartPrint("Recevie UDP message:\r\n");
uartPrint("UDP Head:\r\n");
uartPrint("Source Port:%d\r\n",ntohs(*(uint16_t *)(udp)));
uartPrint("Destination Port:%d\r\n",ntohs(*(uint16_t *)(udp+)));
uartPrint("Total Length:%d bytes\r\n",ntohs(*(uint16_t *)(udp+)));
uartPrint("Checksum:0x%04x\r\n",ntohs(*(uint16_t *)(udp+)));
uartPrint("UDP Data:\r\n");
for(i=;i<len-;i++)
{
uartPrint("%c",udp[+i]);
}
uartPrint("\r\nsending UDP Data...\r\n");
udpsend(srcIp, udp, len, mac);
uartPrint("sent UDP Data.\r\n\r\n");
}
// ½ÓÊÕµ½IP°üµÄ´¦Àí
void ipRcv(uint8_t * frame, uint32_t frameLen, uint8_t * mac)
{
uint16_t ipLength, flag;
uint32_t srcIp, dstIp; if (frameLen < )
{
return;
} if (calcChecksum((uint16_t *)frame, ))
{
// УÑéºÍ²»ÕýÈ·
return;
} if (frame[] != 0x45)
{
// IP VERSION ӦΪ4£¬³¤¶ÈӦΪ20£¨5¸öbit32£©×Ö½Ú¡£
return;
} // ignore Type Of Service ipLength = ntohs(*(uint16_t *)&frame[]); // ignore identification flag = ntohs(*(uint16_t *)&frame[]); if (!(flag & DONT_FRAGMENT))
{
// IP¿ÉÒÔ±»·Ö°ü£¬µ«ÎÒÃÇÖ»´¦Àí²»·Ö°üµÄÇé¿ö¡£ if (flag & MORE_FRAGMENT)
{
// ·Ç×îºóµÄÒ»°ü£¬¶ªÆú¡£
return;
} // ÊÇ×îºóÒ»°ü¡£ if (flag & FRAGMENT_OFFSET)
{
// ÊÇ×îºóÒ»°ü£¬ÇÒÆ«ÒÆÁ¿²»Îª0£¬Ò²¶ªÆú¡£
return;
} // ×îºóÒ»°ü£¬ÇÒÆ«ÒÆÁ¿Îª0£¬ÊÇÕû°ü£¬´¦Àí£¡
} if (frameLen < ipLength)
{
return;
} // ignore fragment offset //ttl = (uint32_t)frame[8]; //srcIp = (frame[12] | (frame[13]<< 8) | (frame[14] << 16) | (frame[15] << 24));
//dstIp = (frame[16] | (frame[17]<< 8) | (frame[18] << 16) | (frame[19] << 24)); srcIp = *(uint16_t *)(frame + ) | ((uint32_t)*(uint16_t *)(frame + ) << );
dstIp = *(uint16_t *)(frame + ) | ((uint32_t)*(uint16_t *)(frame + ) << ); if ((dstIp != g_ethIpAddr) && (dstIp != 0x0100007F) && (dstIp != 0xffffffff))
{
return;
} // if (frame[9] != PROT_ICMP)
// {
// // ·ÇICMP°ü£¬Ôݲ»´¦Àí
// return;
// }
if(frame[] == PROT_UDP)
{
//αͷ²¿
UDPChecksum=(uint8_t *)g_ipSndBuffer;
memcpy(UDPChecksum,frame+,);
memcpy(UDPChecksum+,frame+,);
UDPChecksum[]=;
UDPChecksum[]=frame[];
udpRcv(srcIp,frame + , ipLength - ,mac);
} if (frame[] == ICMP_ECHO_REQUEST)
{
icmpRcvRequest(srcIp, frame + , ipLength - , mac);
}
} // IP²ã½ÓÊÕMAC²ãÊý¾ÝÖ¡µÄº¯Êý
uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen)
{
//0xFFFF ¹ã²¥·½Ê½
if ( ((*(uint16_t *)block == 0xFFFF) && (*(uint16_t *)(block + ) == 0xFFFF) && (*(uint16_t *)(block + ) == 0xFFFF))
||(memcmp(block, g_ethMacAddr, ) == ))
{
// ÊÇ·¢¸ø±¾»úµÄ¡£
switch (ntohs(*(uint16_t *)(block+)))
{
case MAC_TYPE_ARP:
arpRcv(block + , frameLen -);
break;
case MAC_TYPE_IP:
ipRcv(block + , frameLen - , block+);
break;
default:
break;
}
}
return ;
} void ipInit(uint8_t * mac, uint32_t ip)
{
memcpy(g_ethMacAddr, mac, );
g_ethIpAddr = ip;
}
通过上面代码,实现UDP报文接收与发送,实现UDP数据通讯。
基于PLC1850平台的UDP报文接收与发送的更多相关文章
- C#UDP(接收和发送源码)源码完整
C#UDP(接收和发送源码)源码完整 最近做了一个UDP的服务接收和发送的东西.希望能对初学的朋友一点帮助. 源码如下: 一.逻辑--UdpServer.cs using System;using S ...
- 基于X86平台的PC机通过网络发送一个int(32位)整数的字节顺序
1.字节顺序 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端.大端两种字节顺序.小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处:大端字节序是高字节数据存 ...
- 基于PLC1850平台的ICMP包请求与响应
一.以太网IP包报文格式 IP包是连接在以太网首部(以太网目的MAC地址(6个字节)+以太网源MAC地址(6个字节)+帧类型(2个字节))之后. IP报文中各个字段分析如下: ①.版本:在IP报文中, ...
- 基于PLC1850平台的ARP包请求与响应
一.以太网ARP报文格式 ①.以太网目的地址:占6个字节(接收方的MAC地址,不清楚时发广播地址:FF-FF-FF-FF-FF-FF) ②.以太网源地址:占6个字节(发送方的MAC地址) ③.帧类型: ...
- UDP信息接收与发送
转载:http://www.cnblogs.com/sunev/archive/2012/08/08/2627247.html 一.摘要 总结基于C#的UDP协议的同步通信. 二.实验平台 Visua ...
- Kcptun 是一个非常简单和快速的,基于KCP 协议的UDP 隧道,它可以将TCP 流转换为KCP+UDP 流
本博客曾经发布了通过 Finalspeed 加速 Shadowsocks 的教程,大家普遍反映能达到一个非常不错的速度.Finalspeed 虽好,就是内存占用稍高,不适合服务器内存本来就小的用户:而 ...
- 项目总结22:Java UDP Socket数据的发送和接收
项目总结22:Java UDP Socket数据的发送和接收 1-先上demo 客户端(发送数据) package com.hs.pretest.udp; import java.io.IOExcep ...
- 基于Zynq平台的EtherCAT主站方案实现
作者:陈秋苑 谢晓锋 陈海焕 广州虹科电子科技有限公司 摘 要:EtherCAT 是开放的实时以太网通讯协议,由德国倍福自动化有限公司研发.EtherCAT 具有高性能.低成本.容易使用等特点,目前在 ...
- 基于Linux平台的libpcap源码分析和优化
目录 1..... libpcap简介... 1 2..... libpcap捕包过程... 2 2.1 数据包基本捕包流程... 2 2.2 libpcap捕包过程... ...
随机推荐
- T分布
# T分布 # 1.T分布是统计分布的一种,同卡方分布(X2分布),F分布并称为三大分布 2.T分布又叫student-t分布,常用于根据小样本来估计呈正太分布且方差值未知的样本的均值(如果总体的方差 ...
- Node.js_Buffer 缓冲区
Buffer 缓冲区 虽然 JavaScript 支持未操作,但是并没有 二进制数据 的原生 node 引入了 Buffer 类,用于操作二进制数据 是 V8 引擎的扩展,实际上是对内存的直接分配 每 ...
- Android makefile
LOCAL_PATH := $(call my-dir) { call函数:根据不同的参数和函数得到不同的值my-dir函数: 获取当前含有.mk的路径LOCAL_PATH: 定位源文件的位置 } # ...
- ffmpeg日志调式
1.播放器打印输出调试日志:ffplay -v debug $URL2.播放器打开详细调试日志:./ffplay -loglevel 563.修改源码修改日志级别: 1)log.c中:stati ...
- uc/os iii移植到STM32F4---IAR开发环境
也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...
- 2018-2019-2 网络对抗技术 20165311 Exp2 后门原理与实践
2018-2019-2 网络对抗技术 20165311 Exp2 后门原理与实践 后门的基本概念 常用后门工具 netcat Win获得Linux Shell Linux获得Win Shell Met ...
- action,func简洁用法
new Action(() => { }).Invoke();new Action(() => { })(); new Func<int, int>(s => { ...
- spring 数据库多数据源路由
项目中需要根据不同业务进行分库,首先是将业务不同业务映射到不同过的数据库( biz --> db,可能存在多对一情况), 查看springjdbc源码发现AbstractRoutingDataS ...
- 解决nohup中不写入日志的问题
(一)问题描述: nohup 你的程序命令 如: nohup python manage.py runserver 0.0.0.0:6789 (此shell窗口1不要关,另外开一个shell窗口2 ...
- tomcat部署公共jar包
如果每次打war包都要把所有依赖jar放在WEB-INF/lib下,是很傻的做法,war包很大,也浪费内存.参考之前jboss上部署公共jar的经验,tomcat实现起来想来也不困难. 1. 参照ma ...