基于uCOS-II的UDP网络编程
---------------------------------------------------------
Author :tiger-john
WebSite :blog.csdn.net/tigerjb
Email :[email protected]
开发环境 硬件环境:LPC2200
操作系统:UC/OS-II操作系统
编译环境:ADS1.2
Update-Time : 2011年2月21日星期一
Tiger声明:本人鄙视直接复制本人文章而不加出处的个人或团体,
但不排斥别人转载tiger-john的文章,只是请您注明出处并和本人
联系或留言给我。3Q
---------------------------------------------------------
一. 基于UCOS-II操作系统的UDP网络编程
1.UDP网络编程的组成部分
Ø 启动任务:负责UDP的初始化,创建通信工具和轮训检测是否有数据报到来。
Ø UDP数据处理任务:负责UDP报文的处理
Ø UDP服务例程:实现数据的收发。
二. 启动任务
1. 启动任务的功能
l 负责初始化UDP。
l 创建UDP数据处理处理任务和UDP服务例程。
l 轮训检测是否有数据到来。
2.UDP初始化由那及部分组成
1>初始化网络端口地址
通过调用SetNetPort()函数来设置主机IP地址网关地址,子网掩码和主机物理地址。
SetNetPort();
2>初始化RTL8019芯片
通过调用InitNic()函数初始化RTL9019以太网芯片对RTL8019芯片的工作寄存器进行设置。
InitNic(0);
3>初始化ARP函数
通过调用Initial_arp()函数初始化ARP。
Initial_arp();
4>初始化UDP
通过调用Udp_Initial函数初始化UDP。
Udp_Initial();
3.启动任务程序
/********************************************************************
** Function name: TASK0
** Descriptions: 创建任务TASK1(udp数据处理任务)、TASK2(udp服务例程),分配信号量
** input parameters: 无
** output parameters: 无
** Returned value: 无
********************************************************************/
void Task0(void *pdata)
{
UBYTE iii;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
TargetInit();
OSTaskCreate(Task1,(void *)0, &TaskStk1[1000 - 1],3);
OSTaskCreate(Task2,(void *)0, &TaskStk2[1000 - 1],4);
UDP_INIT();
SetNetPort();
InitNic(0); //RTL8019芯片初始化,在global.c中定义
Initial_arp();
Udp_Initial();
while(1)
{
OSTimeDly(4);
do
{
iii=Rec_Packet();//监控是否有数据到来
}
while(iii!=0);
}
}
三. UDP服务例程序任务
1. UDP服务例程任务的功能:
Ø 创建套接字
Ø 绑定本地IP和端口与套接字相连
Ø 实现数据的接发
2..UDP服务例程有那几部分组成
3.UDP服务例程中所用到的API函数接口:
A.socket()函数
1)应用程序在使用套接口通信前,必须要拥有一个套接口,使用socket()函数给应用程序创建一个套接口。
2)函数socket()的原型
SOCKET * socket(uint16 af,uint16 type,uint16 protocol)
该函数功能是从SOCKET pool中分配一个SOCKET插口,供应用程序使用。
其参数说明如下:
1>参数af:表示要使用的协议地址族。
Ø PF_INET:
Ø AF_INET:
在zlg_socket.h中定义:
#define PF_INET 0
#define AF_INET 1
2>参数type:描述套接口的类型
Ø SOCK_STREAM:对应TCP协议
Ø SOCK_DGRAM:对应UDP协议
在zlg_socket.h中定义:
#define SOCK_STREAM 0
#define SOCK_DGRAM 1
3>参数protocol:分配SOCKET协议的类型。
SOCKET协议的类型:
Ø TCP_PROTOCOL:表示应用TCP协议和上面的type要一致。
Ø UDP_PROTOCOL:表示应用UDP协议和上面的type要一致。
在zlg_socket.h中定义:
#define TCP_PROTOCOL 0
#define UDP_PROTOCOL 1
4>返回值:函数执行成功,返回SOCKET*指针指向的一个SOCKET,失败返回NULL。
3)程序实例:
s=*socket( 0,SOCK_DGRAM, UDP_PROTOCOL);
B.bind()函数
1)当socket()函数创建一个套接口后,需要将该套接口与该主机上提供服务的某端口联系在一起。
2)函数bind()的原型
int bind(SOCKET * s,struct sockaddr * name,uint 16 namelen)
本函数功能是将IP地址和端口绑定到一个SOCKET 指针* sock指向的s。
其参数说明如下:
1>SOCKET * s:指向被绑定的SOCKET,它是socket()函数调用成功时返回的值。
2>struct sockaddr * name:是一个与指定协议有关的地址结构指针,存储了套接口的地址信息。
struct sockaddr{
uint16 sin_family;
uint8 sin_addr[4];
uint16 sin_port;
};
3> namelen:表示地址参数的(name)的长度。
4>返回值:成功返回值为0。
3)程序实例:
iii=bind((SOCKET*)&s,(struct sockaddr*)&clientaddr,sizeof(clientaddr));
C.sendto()函数
1)对于无连接的套接口,使用sendto()函数来发送一个数据报文。
2)函数sendto()的原型
uint16 sendto(SOCKET s,uint8 *buff,uint16 len,int flags,struct sockaddr *to,uint16 tolen)
向指定SOCKET *sock插口发送数据,由UDP使用。
其参数说明如下:
1>SOCKET s:本地套接字。
2> uint8 * buff:待发送数据的缓冲区。
3>uint16 len:指明buf缓冲区中要发送的数据长度。
4>int flags:调用方式
5>struct sockaddr * to:指明发送数据的目的套接口地址。
6>uint16 tolen: to所指的地址长度。
7>返回值:为发送数据的字节数。
3)程序实例:
sendto(s,rec_buffer,10,0, (struct sockaddr*)&servaddr, sizeof(servaddr) );
D.recvfrom()函数
1)对于无连接的套接口,通过recvfrom()函数从套接口上接收一个数据报文,并报存发送数据的源地址。
2)函数recvfrom()的原型
uint16 recvfrom(SOCKET *s,uint8 *buff,uint16 len,int flags,struct sockaddr * from,uint16 *fromlen)
函数的参数说明如下:
1> SOCKET s :标识一个套接口的描述字。
2>uint8 * buf:接收数据的缓冲区。
3>uint16 len:接收数据缓冲区的长度。
4> int flags :调用操作方式。
5>struct sockaddr *from: 指明接收数据的目的套接口地址。
6>uint16 *fromlen: 指向from缓冲区的长度值
7>返回值:为已读取的字节数。
3)程序实例:
recvfrom(s,rev_buffer,100,0,(struct sockaddr*)&serveraddr,&iii);
E.closesocket()函数
1)一个套接口不再使用时一定要关闭这个套接口,以释放与该套接口关联的所有资源,包括等候处理的数据。
2)函数closesocket()函数的原型
int closesocket( SOCKET s )
函数参数说明如下:
1> SOCKET s:表示即将被关闭的套接口。
3)程序的实例:
closesocket(s )
4.UDP服务例程的程序:
/********************************************************************
** Function name: TASK2
** Descriptions: UDP服务例程,实现数据的收发
** input parameters: 无
** output parameters: 无
** Returned value: 无
********************************************************************/
void Task2(void *pdata)
{
uint8 rec_buffer[10];
uint8 add[20]={"Hello tiger-john!"};
SOCKET s;
int send_coute;
int rec_coute;
uint16 iii;
struct sockaddr servaddr,clientaddr;
PINSEL1&=0xfffffcff; //P0.20定以为GPIO是具体情况而定
OSTimeDly(60);
servaddr.sin_family=0;
servaddr.sin_addr[1]=168;
servaddr.sin_addr[2]=0;
servaddr.sin_addr[3]=55;
servaddr.sin_port=1025;
OSTimeDly(60);
s=*socket( 0,SOCK_DGRAM, UDP_PROTOCOL);
clientaddr.sin_family=0;
clientaddr.sin_addr[0]=192;
clientaddr.sin_addr[1]=168;
clientaddr.sin_addr[2]=0;
clientaddr.sin_addr[3]=174;
clientaddr.sin_port=1025;
iii=bind( (SOCKET * )&s, (struct sockaddr*)&clientaddr,sizeof(clientaddr));
while(1)
{
rec_coute = recvfrom(s,rec_buffer,10,0,(struct sockaddr *)&servaddr,&iii);
if(rec_coute > 0)
{
if(rec_buffer[0] == 'A')
{
//如果接收到的数据首字母是A,则把接收到的数据直接返回
send_coute = sendto(s,rec_buffer,rec_coute,0, (struct sockaddr*)&servaddr, sizeof(servaddr) );
}
else
{
//否则发送"tiger-john"给上位机
send_coute = sendto(s,add,20,0,(struct sockaddr *)&servaddr,sizeof(servaddr));
}
}
}
}
四.完整程序
情景:接收上位机发送的数据,若上位机发送数据的首字母为A时将接收到的数据再发送给上位机,否则发送tiger-john给上位机。
/****************************Copyright(c)*******************************
** 西安邮电学院
** graduate school
** XNMS实验室
** Author:冀博
** Time:2011年2月21日
** http://blog.csdn.net/tigerjb
**
**--------------FileInfo-------------------------------------------------------------------------------
****************************Copyright(c)******************************/
#define MSG_QUEUE_SIZE 20
#define TaskStkLengh 3000
OS_EVENT *RecPackedFlag;
OS_EVENT *RecBufOverFlowFlag;
OS_EVENT *RecPingPackedFlag;
OS_STK TaskStk0[TaskStkLengh];
OS_STK TaskStk1[1000];
OS_STK TaskStk2[1000];
void Task0(void *pdata); //Task0 任务0
void Task1(void *pdata); //Task1 任务1
void Task2(void *pdata); //Task2 任务2
/********************************************************************
** Function name: UDP_INIT
** Descriptions: 初始化网络地址,RTL8019,ARP和UDP
** input parameters: 无
** output parameters: 无
** Returned value: 无
********************************************************************/
void UDP_INIT(void )
{
SetNetPort();
InitNic(0); //RTL8019芯片初始化,在global.c中定义
Initial_arp();
Udp_Initial();
}
/*********************************************************************
* Function name: main()
** Descriptions: 创建任务TASK0任务
** input parameters: 无
** output parameters: 无
** Returned value: 无
********************************************************************/
int main (void)
{
UBYTE iii;
OSInit();
OSTaskCreate(Task0,(void *)0, &TaskStk0[TaskStkLengh - 1],2);
RecPackedFlag= OSSemCreate(0);
RecBufOverFlowFlag= OSSemCreate(0);
RecPingPackedFlag= OSSemCreate(0);
SendFlag= OSSemCreate(1);
RecUdpQFlag= OSQCreate(&RecUdpQ[0],Q_Max_Size);
OSStart();
}
/********************************************************************
** Function name: TASK0
** Descriptions: 创建任务TASK1(udp数据处理任务)、TASK2(udp服务例程),分配信号量
** input parameters: 无
** output parameters: 无
** Returned value: 无
********************************************************************/
void Task0(void *pdata)
{
UBYTE iii;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
TargetInit();
OSTaskCreate(Task1,(void *)0, &TaskStk1[1000 - 1],3);
OSTaskCreate(Task2,(void *)0, &TaskStk2[1000 - 1],4);
UDP_INIT();
SetNetPort();
InitNic(0); //RTL8019芯片初始化,在global.c中定义
Initial_arp();
Udp_Initial();
while(1)
{
OSTimeDly(4);
do
{
iii=Rec_Packet();//监控是否有数据到来
}
while(iii!=0);
}
}
/*********************************************************************
* Function name: TASK1
** Descriptions: UDP数据处理任务
** input parameters: 无
** output parameters: 无
** Returned value: 无
********************************************************************/
void Task1(void *pdata)
{
void * UdpTemp;
uint8 eer;
while (1)
{
UdpTemp=OSQPend(RecUdpQFlag,0,&eer);
if(eer==OS_NO_ERR)
{
Udp_Process((Rec_Ptr *)UdpTemp);
eer=eer;
}
}
}
/********************************************************************
** Function name: TASK2
** Descriptions: UDP服务例程,实现数据的收发
** input parameters: 无
** output parameters: 无
** Returned value: 无
********************************************************************/
void Task2(void *pdata)
{
uint8 rec_buffer[10];
uint8 add[20]={"Hello tiger-john!"};
SOCKET s;
int send_coute;
int rec_coute;
uint16 iii;
struct sockaddr servaddr,clientaddr;
PINSEL1&=0xfffffcff; //P0.20定以为GPIO是具体情况而定
OSTimeDly(60);
servaddr.sin_family=0;
servaddr.sin_addr[1]=168;
servaddr.sin_addr[2]=0;
servaddr.sin_addr[3]=55;
servaddr.sin_port=1025;
OSTimeDly(60);
s=*socket( 0,SOCK_DGRAM, UDP_PROTOCOL);
clientaddr.sin_family=0;
clientaddr.sin_addr[0]=192;
clientaddr.sin_addr[1]=168;
clientaddr.sin_addr[2]=0;
clientaddr.sin_addr[3]=174;
clientaddr.sin_port=1025;
iii=bind( (SOCKET * )&s, (struct sockaddr*)&clientaddr,sizeof(clientaddr));
while(1)
{
rec_coute = recvfrom(s,rec_buffer,10,0,(struct sockaddr *)&servaddr,&iii);
if(rec_coute > 0)
{
if(rec_buffer[0] == 'A')
{
//如果接收到的数据首字母是A,则把接收到的数据直接返回
send_coute = sendto(s,rec_buffer,rec_coute,0, (struct sockaddr*)&servaddr, sizeof(servaddr) );
}
else
{
//否则发送"tiger-john"给上位机
send_coute = sendto(s,add,20,0,(struct sockaddr *)&servaddr,sizeof(servaddr));
}
}
}
}