TCP/IP(网络层与传输层)

Download Report

Transcript TCP/IP(网络层与传输层)

TI C64x的网络开发应用技术
作者:[email protected].
讨论的主要内容
OSI和TCP/IP网络层次模型
SOCKET函数
TI DSP平台下网络开发工具——NDK
NDK的结构,基本使用方法
NDK的web server开发
NDK的流媒体组播开发
NDK使用经验总结
OSI和TCP/IP网络层次模型
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层
OSI模型
抽象的数据
应用层
传输层
网络层
物理层
TCP/IP模型
开放式系统互联模型(ISO) 结构完整严谨,设计先于实现,体系复杂, 而过于理想
各层有不同的协议
协议的开销

多样的
物理的数据
数据包的封装,解封装
➲
封装
指在发送数据过程中,数据自上而下经过每一
层时,每层为数据添加上特定的头部/尾部信息的操
作。
应用层 →协议数据头(HTTP头,RTP头…)
传输层 →UDP头 TCP头
网络层 →IP头
物理层 →MAC地址头
解封装
所谓解封装是指在接收方发生的自下而上的过
程逐层的去掉头部以及尾部信息
TCP/IP物理层
➲
1,OSI模型中的物理层, 此层规范了通讯设备的
电气特性和物理特性,功能上为数据链路层提
供物理连接。在其上串行传送比特流。
RS232,以太网,FDDI,令牌环网,WIFI, IrDA
➲
2,OSI模型中的数据链路层.包括LLC(Logic
Link Control ) 和MAC(媒体访问控制器)子层
LLC负责与上层(网络层)通讯,
MAC负责对物理层的控制。
本层的典型设备是SWITCH(交换机)
ADLS拨号所使用的PPPoe协议,也是建立在此层次上的
TCP/IP(网络层与传输层)
➲
3、网络层:本层的作用是负责对数据包的路由工作。
路由表的建立,维护,数据包的转发等等.(IP协议工作的层)
典型设备:路由器
➲
4、传输层:本层将应用数据分包,建立端到端的虚连接,提供可靠
或者不可靠传输。
TCP传输
特点:流式传输(stream):需要分包
面向连接(通过“滑动窗口”等方法确保数据准确)
提供可靠的传输服务——可靠性高
 UDP传输
特点: 包式传输(packet):通常不需要分包
无连接:不需要虚连接,可能会丢包,乱序
提供尽力而为(Best-Effort)的服务——效率


ARP,ICMP(Internet Control Message Protocol)……
TCP/IP(应用层)
➲
5、OSI会话层:本层负责两个应用之间会话
的管理和维护。
➲
6、OSI表示层:本层解决数据的表示、转换
问题,是人机之间通讯的协调者,如进行二
进制与ASCII码的转换。
➲
7、OSI应用层:本层是人机通讯的接口。
HTTP,FTP,POP3,SMTP,RTP…….
举例:UDP数据包结构
UDP数据包结构举例
UDP数据包结构举例
没有描述包顺序的信息,因此收方无法判断包颠倒/包重复/包丢失
TCP数据包结构举例
TCP数据包结构举例
TCP数据包结构举例
数据包结构中重要字段
●TTL(Time To Live,生存时间):每经过路由
器一次,此值减一。如果该值为0路由器就不会再
转发此数据包。(IP层)
●Protocol(协议):网络层和传输层之间的通讯
接口,用于识别传输层的传输协议。
●Identification(序号):对每发送的一个数据包
进行编号。注意:收方不能依靠这个标记判断包连
续
基本Socket函数的介绍
Socket接口是TCP/IP网络的API,Socket接口
定义了许多函数或例程,开发者用它们来开发
TCP/IP网络上的应用程序。要学Internet上的
TCP/IP网络编程,必须理解Socket接口。

linux/window下网络开发,以及dsp下网络开发的相似性
Socket函数的介绍
1.UDP Send Client
SOCKET socket( int af, int type, int protocol );
int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
int sendto(SOCKET s, void *pbuf, int size, int flags,
struct sockaddr* pName, int len );
2.UDP Recive Client
SOCKET socket( int domain, int type, int protocol );
int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
Int recvfrom(SOCKET s, void *pbuf, int size, int flags,
struct sockaddr* pName, int *plen );
Socket函数的介绍
3. TCP Client
SOCKET socket( int domain, int type, int protocol );
int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
int connect( SOCKET s, struct sockaddr* pName, int len );
int recv( SOCKET s, void *pbuf, int size, int flags );
int send( SOCKET s, void *pbuf, int size, int flags );
4. TCP Server
SOCKET accept( SOCKET s, struct sockaddr* pName, int *plen );
int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
int listen( SOCKET s, int maxcon );
SOCKET accept( SOCKET s, struct sockaddr* pName, int *plen );
int recv( SOCKET s, void *pbuf, int size, int flags );
int send( SOCKET s, void *pbuf, int size, int flags );
Socket函数的介绍
5.设置读取网络参数
int setsockopt( SOCKET s, int level, int op,
void *pbuf, int bufsize );
int getsockopt( SOCKET s, int level, int op,
void *pbuf, int *pbufsize );
设置buffer大小、超时时间,TTL生存时间,TCP分包大小……..
6.读取一个有连接socket的远端点信息
int getpeername( SOCKET s, PSA pName, int *plen );
7.读取一个socket的近端点信息(bind参数)
int getsockname( SOCKET s, PSA pName, int *plen );
8. 通过域名获得ip地址
struct hostent * gethostbyname(const char* name);
TI DSP平台下网络开发工具——
NDK
Code Composer Studio™ (CCStudio)
Development Tools
TI 推出的for TI DSP的集成开发环境,包括
IDE,编译器,优化器,调试器,DSP模拟器
等,还支持很多JTAG口上的高级功能(RTDX)。
编译优化器支持汇编,C , C++语言,对于TI
DSP程序的开发,基本都在CCS上进行。
版本: V2.2 V3.0 V3.3
➲ DSP/BIOS
由TI开发的,运行在TI DSP平台上的,具有
简单操作系统功能的函数包。它具有简单的内存
管理,多任务调度,任务(Task)间通讯
(Semaphore, Mailbox, Queue, Resource
Lock…..)等。
版本:V4.9 V5.2 V5.31
➲
TI DSP平台下网络开发工具——
NDK
Network Developer's Kit
NDK是TI提供的一个相对完整的TCP/IP
Stack及一些网络工具包,还集成了一些常用
的网络服务器组件。
NDK的版本


➲
有1.61, 1.71, 1.92。
每个版本又分两个不同的模式,其中一个是有
driver的source code。
哪里得到?

一般购买开发板,会附带一个安装包。
NDK目录结构
➲
安装文件
100_O_NDK_TMS320_1_92_00_22.exe
Ndk的安装没有路径限制
ndk相关文档
➲
➲
➲
➲
➲
SPRU523 —TMS320C6000 Network
Developer's Kit (NDK) Software User's Guide
SPRU524 —TMS320C6000 Network
Developer's Kit (NDK) Programmer’s
Reference Guide.
SPRU189 —TMS320C6000 DSP CPU and
Instruction Set Reference Guide.
SPRU198 —TMS320C6000 Programmer's
Guide.
SPRU509 —TMS320C6000 Code Composer
Studio ™Development Tools v3.3 Getting
Started Guide.
NDK介绍
NDK把操作系统(DSP/BIOS)抽象为OS
Adaptation Layer(操作系统适应层),以适应不同
的操作系统,它对应OS.LIB.
NDK把底层硬件抽象成Hardware
Abstraction Layer(硬件抽象层),以适应不同的
底层硬件接口,它对应HAL.LIB.
NDK工作结构图
NDK功能
➲
➲
➲
➲
➲
➲
➲
➲
➲
IP Stack
DHCP client
DNS client
IGMP (Internet Group Management Protocol)
DHCP Server
DNS Server
HTTP Server
NAT Service (Network Address Translation)
………
把NDK添加到项目中
➲
配置DSP/BISO ,(tcf文件,cdb文件)
➲
包含h文件,链接lib文件
➲
配置DNK所使用的内存块(cmd文件)
➲
配置启动NetControl模块
把NDK添加到项目中
1.DSP/BIOS修改(项目中的cdb文件)
增加PRD object (Periodic Function Manager)
定期调用位于NDK的驱动层的函数
llTimerTick().
这个调用时间间隔需要配置为100ms
把NDK添加到项目中
增加HOOK Object
NDK运行时,需要使用一些各个运行task的环
境信息. 为此需要在DSP/BIOS的hook module 模块
建立一个hook,这个hook调用了
NDK_hookInit(),NDK_hookCreate()这两个函数.
把NDK添加到项目中
➲
包含头文件
把NDK下inc目录,增加到.h的搜索路径中
通常在project的项目属性中修改(.pjt)
➲
在项目中链接NDK的LIB库文件
NETCTRL.LIB
HAL_xxx.LIB
NETTOOL.LIB
STACK.LIB
OS.LIB
MiniPrintf.LIB
需要注意CCStudio Project Link Order
通常在 .cmd( Linker-command file )文件中设置
把NDK添加到项目中
配置NDK 的所用到的Memory block(不是必须的)
.far:NDK_PACKETMEM —packet buffer memory
The size required is normally 32k bytes to 48k
bytes.
.far:NDK_MMBUFFER — a scratchpad memory
default is less than 48k bytes.(adjustable)
.
far:NDK_OBJMEM — other large data buffe
the example in project CMD file:
SECTIONS
{
.far:PACKETMEM: {} > MYSDRAM
.far:MMBUFFER: {} > MYSDRAM
.far:OBJMEM: {} > MYSDRAM
}
启动NDK task
➲
创建NDK使用的task
struct TSK_Attrs attr;
attr=TSK_ATTRS;
attr.priority=8;
attr.name="network";
attr.stack = 0;
attr.stacksize = 15*1024; // <= 32*1024 >=4*1024
attr.stackseg = extHeap;
htsk_network=TSK_create((Fxn)network_main, &attr);
if(htsk_network == NULL)
{
printf("TSK_create((Fxn)network_main error!\n");
exit(0);
}
NDK Task中的主要工作
➲
初始化NetControl
➲
配置NetControl
➲
运行NetControl
初始化NetControl
➲
1.初始化协议栈,及协议栈组件
int NC_SystemOpen (int Priority, int OpMode);
注意此函数会自动调整NDK task的Priority 的优先级(6,7,8)
另外所有使用NDK的其他task的Priority不能超过NDK
rc = NC_SystemOpen( NC_PRIORITY_HIGH,
NC_OPMODE_INTERRUPT );
配置NetControl
创建一个NDK 的配置结构.
HANDLE hCfg = CfgNew();
Configuration Functions:
CfgNew() Create a new configuration
CfgFree() Destroy a configuration
CfgSetDefault() Set default configuration
CfgGetDefault() Get default configuration
CfgLoad() Load configuration from a linear memory buffer
CfgSave() Save configuration to a linear memory buffer
CfgAddEntry() Add a configuration entry to a configuration
CfgRemoveEntry() Remove entry from configuration
CfgGetEntryCnt() Get the number of item instances for a tag/item pair
CfgGetEntry() Get a referenced handle to a configuration entry
CfgEntryGetData() Get configuration entry data from entry handle
CfgEntrySetData() Replace data block of entry data using entry handle
配置NetControl
3.配置NetControl
int CfgAddEntry(HANDLE hCfg, uint Tag,
uint Item, uint Mode, uint Size,
UINT8 *pData, HANDLE *phCfgEntry);
Tag
Item
Mode
:Tag value of new entry
:Item value of new entry
:Mode flags for how to add entry
需要要设置的信息有:
Network Hostname
IP Address and Subnet Mask
IP Address of Default Routes
Services to be Executed (DHCP, DNS, HTTP, etc.)
IP Address of name servers
Stack Properties (IP routing, socket buffer size, ARP timeouts, etc.)
Tag种类
CFGTAG_SERVICE
Network Service
CFGTAG_IPNET
IP Network (Address, subnet mask, etc.)
CFGTAG_ROUTE
IP Gateway Route
CFGTAG_CLIENT
IP Client (Client IP, Hostname, etc)
CFGTAG_ACCT
Client user account (name, password, etc.)
CFGTAG_SYSINFO
Global System Information
CFGTAG_OS
Operating System Configuration entry
CFGTAG_IP
IP Stack Configuration entry
配置NetControl的例子
// Add our global hostname
CfgAddEntry( hCfg,
CFGTAG_SYSINFO,CFGITEM_DHCP_HOSTNAME,
0,strlen(HostName), (UINT8 *)HostName, 0 );
//配置IP
CI_IPNET NA;
CfgAddEntry( hCfg, CFGTAG_IPNET, 1, 0,
sizeof(CI_IPNET), (UINT8 *)&NA, 0 );
//配置网关
CfgAddEntry( hCfg, CFGTAG_ROUTE, 0, 0,
sizeof(CI_ROUTE), (UINT8 *)&RT, 0 );
//配置DNS
CfgAddEntry( hCfg, CFGTAG_SYSINFO,
CFGITEM_DHCP_DOMAINNAMESERVER,
0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0 );
配置NetControl的例子
//Highest priority for stack task
rc = 1;
CfgAddEntry( hCfg, CFGTAG_OS,
CFGITEM_OS_TASKPRIHIGH,CFG_ADDMODE_UNIQUE, sizeof(uint),
(UINT8 *)&rc, 0 );
// This code sets up the TCP and UDP buffer sizes
rc = 1664*10;
CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPTXBUF,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
// TCP Receive buffer size (copy mode)
rc = 1664*10;
CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPRXBUF,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
// TCP Receive limit (non-copy mode)
rc = 1664*10;
CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPRXLIMIT,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
// UDP Receive limit
rc = 1664*400;
CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKUDPRXLIMIT,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
配置NetControl的例子
// Timeout of validated route in seconds
rc = 1;
CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_RTKEEPALIVETIME,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
// Max time for connect socket
rc = 100000;
CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTIMECONNECT,
/
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
// Max time in seconds to wait on socket read/write
rc = 1000;
CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTIMEIO,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
启动NetControl
int NC_NetStart(HANDLE hCfg,
void (*NetStartCb)(),
void (*NetStopCb)(),
void (*NetIPCb)(IPN,uint,uint));
do
{
rc = NC_NetStart( hCfg, NetworkOpen,
NetworkClose, NetworkIPAddr );
} while( rc > 0 );
NDK task的例子
DM642 EVM板配套的安装程序安装之
后,会有一个
$(Install_dir)\boards\evmdm642\examples\vi
deo_networking\jpeg_network\jpeg_network
.pjt 项目。
这个项目里有一个network_main.c 的文
件。这个文件展示了ndk的初始化的过程。
在使用ndk之前,要了解这个文件。
NDK 2个重要的回调函数
获得MAC地址
void DM642EMAC_getConfig( UINT8
*pMacAddr, uint *pIntVector );
pMacAddr 返回一个6byte的MAC地址
报告网络联接状态
void DM642EMAC_linkStatus( uint
phy, uint linkStatus )
phy 物理口标识
linkStatus 连接状态
一个UDP Send Client的例子
Char buf[1024];
fdOpenSession( TaskSelf() );
MBX_pend(mbx_audio_decoder,&recv_msg,SYS_FOREVER);
struct sockaddr_in sendinfo;
HANDLE soch = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset(&sendinfo, 0, sizeof(struct sockaddr_in));
sendinfo.sin_family = AF_INET;
sendinfo.sin_len = sizeof(struct sockaddr_in);
sendinfo.sin_addr.s_addr = inet_addr(“192.168.1.100”);
sendinfo.sin_port = htons(8888);
sendto(buf,1024, 0,&(sendinfo), sizeof(struct sockaddr_in));
注意点:
1.如果在一个task中要使用socket函数,必须首先调用fdOpenSession,
之后才能使用任何其它的socket 函数。
2.任务结束的时候需要使用fdCloseSession(). 要不然会有内存泄露。
NDK上Web Server 开发
➲
➲
➲
➲
配置Web Server
增加网页
编写CGI程序
增加网页的身份认证
配置Web Server
通过hCfg,配置Web Server
// Specify HTTP service
CI_SERVICE_HTTP http;
bzero( &http, sizeof(http) );
http.cisargs.IPAddr = INADDR_ANY;
http.cisargs.pCbSrv = &ServiceReport;//一个用于汇报状态的函数
CfgAddEntry( hCfg, CFGTAG_SERVICE,
CFGITEM_SERVICE_HTTP, 0,
sizeof(http), (UINT8 *)&http, 0 );
增加网页
Create (declare) a RAM Based File
void efs_createfile
(char *name, INT32 length, UINT8 *pData);
efs_createfile() Create (declare) RAM based file
efs_destroyfile() Destroy RAM based file
efs_fopen() Open file
efs_fclose() Close file
efs_feof() Check for end of file
efs_fread() Read from file
efs_fseek() Set file position
efs_ftell() Get file position
efs_fwrite() Write to file
efs_rewind() Reset file position to start of file
增加网页
//增加静态页面
efs_createfile(“index.html”,
index_SIZE, index);//数据指针
efs_createfile("leftindex.htm",
leftindex_SIZE,leftindex);
efs_createfile("jump.htm",
jump_SIZE, jump);
efs_createfile("back.jpg",
back_SIZE,back);
//增加动态页面
efs_createfile(“post.cgi”,
0, (UINT8 *)function_post); //函数指针
efs_createfile(“config.cgi",
0, (UINT8 *)function_config);
编写CGI程序
1.CGI函数定义
static int cgiSample
(int htmlSock, int ContentLength, char *pArgs );
2.分析提交的参数
void save_manual_nat(char *buffer,int *parseIndex)
{
char *key, *value;
do {
key = cgiParseVars( buffer, parseIndex );
value = cgiParseVars( buffer, parseIndex );
if(!strcmp("keyname",key))
{
//use value to do something
}
}while(*parseIndex != -1);
}
编写CGI程序
CGI如何返回数据给client
//http header
httpSendStatusLine(htmlSock, HTTP_OK, CONTENT_TYPE_HTML);
httpSendClientStr(htmlSock, CRLF);
HTTP_AUTH_REQUIRED,HTTP_NOT_FOUND,
HTTP_NOT_ALLOWED ,HTTP_NOT_IMPLEMENTED
//写文件信息
char tempstr[ ] = "ncif.innerHTML = 'SIF';\n";
send(htmlSock,tempstr,strlen(tempstr),0);
//操作完毕
return 1;
Web Server的身份认证
1.NDK内分4个用户组,每个用户组都可以增加多个
用户,用户组与用户组之间处于平级关系。
通过CfgAddEntry( hCfg, CFGTAG_ACCT,
CFGITEM_ACCT_REALM,……..) 来添加用户
2.Web文件中,同一目录下的所有文件具有相同的
保护权限(不包含子目录)。
设置方法如下:
static int OurRelm1 = 1;
static int OurRelm2 = 2;
efs_createfile("%R%",4,(UINT8 *)&OurRelm1);
efs_createfile("advlink/%R%", 4, (UINT8 *)&OurRelm2);
NDK的组播应用
1. 什么是组播(多播)?
组播是一种数据包传输方式,当有多台主机同时成为
一个数据包的接受者时,出于对带宽和CPU负担的考虑,组
播成为了一种最佳选择。主要应用在音视频广播。
2. 组播如何进行工作?
组播,由一台源主机以224.0.0.0-239.255.255.255的
D类地址作为目的地址,发送UDP数据。此时网络中,如果
有其他主机对于这个组的数据有兴趣的,可以申请加入这个
组以接受UDP数据,而其他不是这个组的成员是无法接受到
这个组的UDP数据。
3. 实际中,普通SWITCH,ROUNT 对组播的
处理。
NDK的组播应用
➲
Internet Group Management Protocol (IGMP)
uint IGMPJoinHostGroup
(IPN IpAddr, uint IfIdx);
void IGMPLeaveHostGroup
(IPN IpAddr, uint IfIdx);
IpAddr
IfIdx
:组播地址
:网络界面的序号,单地址时候设为0
NDK的组播应用例子
m_video_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset(&m_audio_SockAddr, 0, sizeof(struct sockaddr_in));
m_audio_SockAddr.sin_family = AF_INET;
m_audio_SockAddr.sin_len = sizeof(struct sockaddr_in);
m_audio_SockAddr.sin_addr.s_addr = ntohl(addr_audio);// D类地址
m_audio_SockAddr.sin_port = htons(AUDIO_PORT);
if(!IGMPJoinHostGroup(m_audio_SockAddr.sin_addr.s_addr,0))
{
printf("error!\n");
return;
}
sendto(m_audio_socket,block->data, block->m_used_size,
0,&(m_audio_SockAddr), sizeof(struct sockaddr_in));
Recvfrom(……………………………………………………)
NDK需要注意的问题
➲
➲
➲
➲
➲
Socket handle不能在 task 之间共享。在移
植一些已经做好的库的时候,这一点限制非
常大。为了能够共享,需要使用 fdShare函
数。
还有其它fdXXX相关的一些函数。适合标准
的socket系列函数差别巨大的地方。
老版本的ndk的FD_CLR 有bug.
fdSelect 函数有bug. 导致中断丢失. 从而导
致系统时钟不准.
socket(...) 函数的返回值为负值. 在使用其
它网络库的时候,需要特别注意.
一些其它需要注意的问题
➲
➲
➲
➲
创建task的时候,如果是动态分配stack的,task
结束以后内存不会被释放,造成内存泄露.
dsp/bios 内置的sscanf 和 snprintf 函数都有
问题.
注意mac地址不要重复.新作的板子经常出现
这个问题.
如果使用dhcp模式注意网络内存在dhcp
server. Ndk的dhcp client兼容性不是特别好.
网络应用----RTP/RTCP协议
➲
Real-time Transport Protocol
通常用于流媒体传输
在RTP的基础上,增加了时间戳,包序
号,源标识等额外的信息。
➲
Real-time Control Protocol
RTP的控制部分
周期性反馈
提供时间同步、阻塞反馈
网络应用----RTP协议
➲
RTP 格式
版本号(V):2bit,目前固定为2
间隙(P):1bit,通常设为0
扩展位(X):1bit,通常设为0
CSRC计数器(CC):4bit,
表示后面的CSRC的数目。
标记位(M):1bit,通常表示为帧边界(帧结束)
净荷类型(PT):7bit,标识了RTP净荷的格式,
比如H263为34,jpeg为26,G723为4,G729为18.
序列号(Sequence Number):16bit,每发送一个包增加1.
时间戳(Timestamp):32bit,以采样时刻为单位
同步源(SSRC):32bit,值随机选择,但需确保在同一
个RTP会话中各个不同的RTP流各不相同。
问题与讨论
➲
进入讨论时间。。。