uIP原始套接字

合集下载

UIP中文文档第五 原始套接字_protosockets_库

UIP中文文档第五 原始套接字_protosockets_库

详细说明:原始套接字(protosocket)为uIP提供了一个与传统BSD套接字接口类似的接口.不同于为传统uIP事件驱动接口写的程序,为原始套接字(protosocket)接口写的程序是顺序方式执行的,并且无需以明确的状态机方式实现.原始套接字(protosocket)只能用于TCP连接.原始大接字(protosocket)库使用"原始线程(protothreads)"来提供顺序控制流.这使得原始套接字在内存方面变得轻量型,但也同时意味着原始套接字继承了"原始线程"的功能限制.每个原始套接字只能生存于单个函数中.自动变量(栈变量)不能跨原始套接字函数调用存在. 注意:由于原始套接字库使用的是"原始线程(protothreads)",在调用原始套接字库函数时,局部变量并不总能得到保存.所以这里建议局部变量的使用要十分小心。

原始套接字库提供了一些无需处理重传和回应的发送数据函数,和一些无需对被分解成多个TCP段的数据进行处理的读取数据函数。

由于每个原始套接字都作为一个“原始线程”来运行,应在使用原始套接字的函数起始处通过调用PSOCK_BEGIN()的方式启用原始套接字。

与之类似,原始套接字可以通过调用PSOCK_EXIT()结束掉。

相关文件:1.psock.h 原始套接字库头文件复制代码相关结构体:1.struct psock_bufstruct psock 代表一个原始套接字。

复制代码相关宏定义:1.。

2.#define PSOCK_INIT(psock, buffer, buffersize) 初始化一个原始套接字。

3.#define PSOCK_BEGIN(psock) 在一个函数中启用一个原始套接字的原始线程。

4.#define PSOCK_SEND(psock, data, datalen) 发送数据。

5.#define PSOCK_SEND_STR(psock, str) 发送一个以零结尾的字符串。

利用原始套接字构造并发送数据包的方法

利用原始套接字构造并发送数据包的方法

利用原始套接字构造并发送数据包的方法摘要:一、原始套接字概述1.定义与作用2.分类与应用场景二、构造数据包1.数据包结构2.常用协议及其封装三、发送数据包1.发送原理2.发送方法与实例四、原始套接字的安全性1.安全风险2.防范措施五、实践与应用1.操作步骤与注意事项2.应用案例分享正文:一、原始套接字概述1.定义与作用原始套接字(Raw Socket)是一种允许用户直接操作网络底层协议的套接字类型。

它允许用户在操作系统层面上构造和发送数据包,而不受协议栈的限制。

原始套接字广泛应用于网络数据包捕获、分析、发送等领域,为开发者提供了极大的灵活性。

2.分类与应用场景原始套接字根据底层协议可分为以下几类:(1)ICMP原始套接字:主要用于处理ICMP协议,如ping命令。

(2)UDP原始套接字:用于无连接的UDP数据传输。

(3)TCP原始套接字:用于建立和维护连接的TCP协议。

(4)IP原始套接字:用于处理IP层数据包,如IPv4和IPv6。

二、构造数据包1.数据包结构网络数据包从下到上分为:链路层、网络层、传输层和应用层。

原始套接字直接操作网络层,因此需要了解各层的数据结构。

(1)链路层:以太网帧,包含目的MAC地址、源MAC地址、类型字段等。

(2)网络层:IP数据报,包含版本、首部长度、服务类型、总长度、标识、标志、片偏移、生存时间、协议、头部校验和、源IP地址、目的IP地址等。

(3)传输层:TCP或UDP段,包含源端口、目的端口、序列号、确认号等。

(4)应用层:根据不同协议,如HTTP、DNS等,包含请求头、响应头、查询字符串等。

2.常用协议及其封装了解各层协议后,需要熟悉如何将这些协议封装到数据包中。

以下以IP协议和UDP协议为例:(1)IP协议封装:设置IP数据报的版本、首部长度、服务类型等,填充源IP地址、目的IP地址,计算头部校验和。

(2)UDP协议封装:设置UDP段的首部,包括源端口、目的端口、长度和校验和。

uip

uip

uIP的ARP协议代码分析之一ARP请求对于一个设备用的ARP协议而言,重要的东西包括三方面:1.一个本地的IP与MAC地址的缓存表.以有对应的更新和查询操作.2.一个发送ARP请求的函数.3.一个处理ARP回复的函数.下面我们来看uIP中是如何实现的(代码见uip_arp.c:首先,定义一个缓存表的数据结构,99行起:struct arp_entry {u16_t ipaddr[2];struct uip_eth_addr ethaddr;u8_t time;};只有三个项,很简单第一项是ip地址,16*2=4*8位的,保存四个八位组.第二项是MAC地址.第三项是缓存更新时间.下来是ARP请求发送函数:/*-----------------------------------------------------------------------------------*//*** Prepend Ethernet header to an outbound IP packet and see if we need* to send out an ARP request.*为传出的IP包添加以太网头并看是否需要发送ARP请求.* This function should be called before sending out an IP packet. The* function checks the destination IP address of the IP packet to see* what Ethernet MAC address that should be used as a destination MAC* address on the Ethernet.*此函数应该在发送IP包时调用,它会检查IP包的目的IP地址,看看以太网应该使用什么目的MAC地址.* If the destination IP address is in the local network (determined* by logical ANDing of netmask and our IP address), the function* checks the ARP cache to see if an entry for the destination IP* address is found. If so, an Ethernet header is prepended and the* function returns. If no ARP cache entry is found for the* destination IP address, the packet in the uip_buf[] is replaced by* an ARP request packet for the IP address. The IP packet is dropped* and it is assumed that they higher level protocols (e.g., TCP)* eventually will retransmit the dropped packet.*如果目的IP地址是在局域网中(由IP地址与子网掩码的与逻辑决定),函数就会从ARP缓存表中查找有*无对应项.若有,就取对应的MAC地址,加上以太网头,并返回,否则uip_buf[]中的数据包会被替换成一个*目的IP在址的ARP请求.原来的IP包会被简单的仍掉,此函数假设高层协议(如TCP)会最终重传扔掉的包.* If the destination IP address is not on the local network, the IP* address of the default router is used instead.*如果目标IP地址并非一个局域网IP,则会使用默认路由的IP地址.* When the function returns, a packet is present in the uip_buf[]* buffer, and the length of the packet is in the global variable* uip_len.函数返回时,uip_buf[]中已经有了一个包,其长度由uip_len指定.*//*-----------------------------------------------------------------------------------*/voiduip_arp_out(void){struct arp_entry *tabptr;/* Find the destination IP address in the ARP table and constructthe Ethernet header. If the destination IP addres isn't on thelocal network, we use the default router's IP address instead.//在ARP表中找到目的IP地址,构成以太网头.如果目的IP地址不在局域网中,则使用默认路由的IP.If not ARP table entry is found, we overwrite the original IPpacket with an ARP request for the IP address. *///如果ARP表中找不到,则将原来的IP包替换成一个ARP请求./* First check if destination is a local broadcast. 首先检查目标是不是广播*/if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) {memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);} else {/* Check if the destination address is on the local network. 检查目标地址是否在局域网内 */if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) {/* Destination address was not on the local network, so we need touse the default router's IP address instead of the destinationaddress when determining the MAC address. 目的地址不在局域网内,所以保用默认路由器的地址来确在MAC地址*/uip_ipaddr_copy(ipaddr, uip_draddr);} else {/* Else, we use the destination IP address. 否则,使用目标IP地址*/uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);}for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {//这里遍历表,对比目的IP与ARP缓存表中的IP.tabptr = &arp_table;if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) {break;}}if(i == UIP_ARPTAB_SIZE) {/* The destination address was not in our ARP table, so weoverwrite the IP packet with an ARP request. 如果遍历到头没找到,将原IP包替换为ARP请求并返回*/memset(BUF->ethhdr.dest.addr, 0xff, 6);memset(BUF->dhwaddr.addr, 0x00, 6);memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);uip_ipaddr_copy(BUF->dipaddr, ipaddr);uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */BUF->hwtype = HTONS(ARP_HWTYPE_ETH);BUF->protocol = HTONS(UIP_ETHTYPE_IP);BUF->hwlen = 6;BUF->protolen = 4;BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];uip_len = sizeof(struct arp_hdr);return;}/* Build an ethernet header. 如果是在局域网中,且在ARP缓存中找到了(如果没找到进行不到这一步,在上面就返回了),则构建以太网头*/memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);}memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);uip_len += sizeof(struct uip_eth_hdr);}以上内容自325行起.下面再总结一下其基本顺序:用IPBUF->ethhdr.dest.addr来存储目的IP地址,它有可能是局域网内一主机IP,也可能是路由器IP(如果是发往外网,即原来的目的IP不在局域网内),还有可能是广播专用的IP. 先看是不是在广播:如果是广播,将IPBUF->ethhdr.dest.addr设为广播IP.再看是不是在局域网内:如果不是,则将IPBUF->ethhdr.dest.addr设为路由器IP.如果在局域网内,查看是否已经存在于ARP缓存表中:如果不在,将要发送的换成ARP请求,返回.如果已存在,则查找使用查找到的MAC地址为IP包添加以太网头.这里还要解释一些细节问题,主要是:1.如何在IP包上添加以太网头2.如果将IP包替换成ARP请求,ARP请求的格式是什么.3.广播地址这些问题将在二楼来说.将IP包替换成ARP请求部分代码(实际上IP包是放在uip_buf[]里的,这里只是将uip_buf[]填充上ARP请求即可),于uip_arp.c的388行:/* The destination address was not in our ARP table, so weoverwrite the IP packet with an ARP request. */memset(BUF->ethhdr.dest.addr, 0xff, 6);memset(BUF->dhwaddr.addr, 0x00, 6);memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);uip_ipaddr_copy(BUF->dipaddr, ipaddr);uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */BUF->hwtype = HTONS(ARP_HWTYPE_ETH);BUF->protocol = HTONS(UIP_ETHTYPE_IP);BUF->hwlen = 6;BUF->protolen = 4;BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];uip_len = sizeof(struct arp_hdr);return;首先解释这里的BUF(于uip_arp.c的116行):#define BUF ((struct arp_hdr *)&uip_buf[0])可见这里的BUF就是uip_buf[],只不过这里将它取做一个struct arp_hdr的结构体:struct arp_hdr {struct uip_eth_hdr ethhdr;u16_t hwtype; //硬件类型u16_t protocol; //协议类型u8_t hwlen;u8_t protolen;u16_t opcode; //操作码struct uip_eth_addr shwaddr; //源以太网地址u16_t sipaddr[2]; //源IP地址struct uip_eth_addr dhwaddr; //目的以太网地址u16_t dipaddr[2]; //目的IP地址};struct uip_eth_hdr {struct uip_eth_addr dest;struct uip_eth_addr src;u16_t type;};这是arp_hdr的第一个成员ethhdr的类型定义,对应图片中的前三项:6+6+2,目的以太网地址,源以太网地址,2字节数据类型(ARP请求和应答为0x0806).struct arp_hdr的第二个成员u16_t hwtype,对应图片中第三项,2字节硬件类型(值为1表示以太网).struct arp_hdr的第三个成员u16_t protocol,对应图片中第四项,2字节要映射的协议地址类型(ip地址为0x0800).struct arp_hdr的第四个成员u8_t hwlen,对应图片中第五项,1字节硬件地址长度(对MAC地址来说为6).struct arp_hdr的第五个成员u8_t protolen,对应图片中第六项,1字节协议地址长度(对IP地址来说为4).struct arp_hdr的第六个成员u16_t opcode,对应图片中第七项,2字节操作码(1 ARP请求,2 ARP应答,3 RARP请求,4 RARP应答,必须字段).struct arp_hdr的第七个成员struct uip_eth_addr shwaddr,对应图片中第八项,6字节源以太网地址.struct arp_hdr的第八个成员u16_t sipaddr[2];,对应图片中第九项,2字节源IP地址.struct arp_hdr的第九个成员struct uip_eth_addr dhwaddr,对应图片中第十项,6字节目标以太网地址.struct arp_hdr的第十个成员u16_t dipaddr[2];,对应图片中第十一项,2字节目标IP地址.上面绿色的表示已经详解的,红字的表示要进一步说明的.这就是一个ARP帧的结构,可以看到,里面的源和目的以太网地址都是重复的.我们再看函数中的代码:memset(BUF->ethhdr.dest.addr, 0xff, 6);memset(BUF->dhwaddr.addr, 0x00, 6);memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);这里四个memset,重复的源和目的以太网地址一起设置了,四个memset对应图片中的1,10,2,8项.但是:对1和10两项,都是源以太网地址,但置的值是不同的,分别为0xff*6和0x00*6.为什么会这样呢?因为他们的用处不一样,见:【相关资料】ARP分组格式(帧格式,报文格式)6+6–以太网的源地址和目的地址,目的地址为全1的为广播地址注意这里说,目的地址为全为1的广播地址.什么意思?当你发送一个ARP请求是,你是想知道一个IP对应的以太网地址(即MAC地址),但是你现在不知道目的主机的以太网地址,你问谁啊?不知道问谁,这种情况下,只能是广播一下了,0xff*6就是广播地址.从图片中可以看到,ARP包是分成两部分的,前6+6+2叫做"以太网首部",它的意义就是"分组是从谁(源地址)发给谁(目的地址)的什么类型(帧类型,请求和应答为0x0806)",第二部分则是内容.来看这个例子:请求帧如下(为了清晰在每行的前面加了字节计数,每行16个字节):以太网首部(14字节)0000: ff ff ff ff ff ff 00 05 5d 61 58 a8 08 06ARP帧(28字节)0000: 00 010010: 08 00 06 04 00 01 00 05 5d 61 58 a8 c0 a8 00 370020: 00 00 00 00 00 00 c0 a8 00 02填充位(18字节)0020: 00 77 31 d2 50 100030: fd 78 41 d3 00 00 00 00 00 00 00 00以太网首部:目的主机采用广播地址,源主机的MAC地址是00:05:5d:61:58:a8,上层协议类型0x0806表示ARP。

UIP中文文档第六 uIP原始线程(protothreads

UIP中文文档第六 uIP原始线程(protothreads

详细说明:“原始线程”是一种轻量级的、无需堆栈的线程。

它主要用于内存极为受限的系统,如深入嵌入式系统、传感器网络等。

“原始线程”是以C代码实现的,为事件驱动的系统提供了线性的代码执行空间。

“原始线程”即可以用在有实时操作系统的系统中,也可以用在没有实时操作系统的系统中。

它在事件驱动的系统上层提供了阻塞上下文,省去了每个线程的单独堆栈空间开销。

原始线程的目标是在没有复杂的状态机或多线程的情况下实现控制顺序流。

原始线程在C语言内部实现了条件阻塞。

原始线程相对于纯事件驱动方法的优势是原始线程提供了可以阻塞函数的顺序代码结构。

在纯事件驱动的方法中,阻塞的实现必须将一个函数手动分成两个部分。

一部分放在阻塞调用前,一部分放在阻塞调用后。

这让使用if()和while()语句变得困难。

原始线程相对于普通线程的优势是,它不需要为每个线程分配堆栈。

在内存受限的系统中,为每个线程分配堆栈空间会占用大量的内存。

相比而言,原始线程的每个线程只需2到12个字节的状态字,具体多大与构架有关。

注意:由于原始线程有阻塞调用中中不需保存堆栈上下文,原始线程阻塞时,局部变量也不再保留。

这意味着局部变量的使用必须十分小心。

如果不确定的话,尽量不要有原始线程中使用局部变量。

主要特性:∙无机器相关代码-代码完成是C写的。

∙不使用错误-倾向于像longjump()这样的函数。

∙很小的RAM开销-每条线程仅两个字节。

∙即可使用OS,也可以不使用。

∙提供阻塞等待而无需多线程或堆栈切换。

主要应用:∙内存受限系统∙事件驱动的协议栈∙深入嵌入式系统∙传感器网络原始线程包括四个基本的操作:初妈化(PT_INIT()),执行(PT_BEGIN()),条件阻塞(PT_WAIT_UNTIL()),和退出(PT_EXIT()).在此之上还有两个方便使用的函数:反向条件阻塞(PT_WAIT_WHILE())和原始线程阻塞(PT_WAIT_THREAD()).见:uIP中文文档第五原始套接字原始线程线的分布是基于一个类似于BSD的协议的。

公开课 原始套接字编程

公开课 原始套接字编程

公开课原始套接字编程一、引言在当今互联网时代,网络编程已成为程序员必备技能之一。

本次公开课将为大家介绍原始套接字编程,通过学习本课程,你将掌握原始套接字的基本概念和实战技巧,为日后的网络编程任务奠定基础。

二、原始套接字编程基本概念1.套接字概述套接字(Socket)是应用程序与底层操作系统之间的接口,允许应用程序在网络中发送和接收数据。

套接字分为客户端和服务器端,通过套接字,客户端可以与服务器端进行通信。

2.原始套接字与封装套接字的区别原始套接字(Raw Socket)是指不经过任何协议封装的套接字,它直接使用底层网络协议(如TCP/IP)进行通信。

封装套接字(Wrapped Socket)则是将套接字包装在某种协议中,如HTTP、FTP等。

3.原始套接字编程的应用场景原始套接字编程适用于需要底层网络控制的情景,如网络数据捕获、网络数据解析等。

此外,它还常用于网络攻击防护和网络安全研究。

三、原始套接字编程实战1.创建原始套接字创建原始套接字需要使用socket函数,如:socket(AF_INET,SOCK_RAW, IPPROTO_IP)。

2.绑定套接字到端口使用bind函数将套接字绑定到指定的本地端口,如:bind(套接字,(struct sockaddr_in *)&local_addr)。

3.监听连接使用listen函数监听连接,如:listen(套接字,5)。

4.接受连接当有新的连接请求时,使用accept函数接受连接,如:accept(套接字,(struct sockaddr *)&remote_addr,& sock)。

5.发送和接收数据使用send和recv函数发送和接收数据,如:send(套接字,发送数据,发送长度);recv(套接字,接收数据,接收长度)。

6.关闭套接字在完成通信后,使用close函数关闭套接字,如:close(套接字)。

四、原始套接字编程进阶话题1.异步I/O编程在处理大量网络数据时,可以使用异步I/O编程提高程序性能,如使用poll、epoll等。

原始接字编程

原始接字编程

北京理工大学珠海学院 孙细斌
原始套接字(Raw Socket)
IP协议:是TCP/IP协议族中最为核心的协议。 它提供不可靠、无连接的服务。所有的 TCP、UDP、ICMP、IGMP数据都被封装 在IP数据报中传送。IP协议头部结构如下:
北京理工大学珠海学院 孙细斌
原始套接字(Raw Socket)
IP协议头部结构如下:
北京理工大学珠海学院 孙细斌
原始套接字(Raw Socket)
ICMP协议介绍: ICMP是“Internet Control Message Protocol” (Internet控制消息协议)的缩写。它是 TCP/IP协议族的一个子协议,用于在IP主 机、路由器之间传递控制消息。控制消息 是指网络通不通、主机是否可达、路由是 否可用等网络本身的消息。这些控制消息 虽然并不传输用户数据,但是对于用户数 据的传递起着重要的作用。
原始套接字(Raw Socket) 利用Raw Socket技术编写基于 ICMP协议的ping命令步骤 (2)定义原始socket对象
Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
北京理工大学珠海学院 孙细斌
原始套接字(Raw Socket)
class ICMPPacket { • public ICMPPacket(byte icmpType,byte subCode,UInt16 checkSum,UInt16 identity,UInt16 sequence,int dataSize) • { • this.icmpType = icmpType; • this.subCode = subCode; • this.checkSum = checkSum; • this.identity = identity; • this.sequence = sequence; • data = new byte[dataSize]; • for (int i = 0; i < dataSize; i++) • { • data[i]=(byte)'Y'; • } • } • }

网络编程_第9讲 原始套接字编程

网络编程_第9讲 原始套接字编程

9.2.3
不需要bind()函数
原始套接字不需要使用bind()函数,因为进行发送和接 收数据的时候可以指定要发送和接收的目的地址的IP。例如 使用函数sendto()和函数recvfrom()来发送和接收数据, sendto()和recvfrom()函数分别需要指定IP地址。 sendto (rawsock, data, datasize, 0, (struct sockaddr *) &to, sizeof (to)); recvfrom(rawsock, data,size , 0,(struct sockaddr)&from, &len) ; 当系统对socket进行了绑定的时候,发送和接收的函 数可以使用send()和recv()及read()和write()等不需要指定 目的地址的函数。
0 类型(8位) 7 8 15 16 代码(8位) 校验和(16位) 31
(此部分不同的类型和代码格式不同)
9.5.3
0 源端口号(16位) UDP数据长度(16位)
UDP头部结构
15 16 目的端口号(16位) 8个字节 UDP校验和(16位) 31
数据
0 source len
15 16 dest
数据
IP头部的结构
15 16 总长度(16位) 标识(3位) 片偏移(13位) 头部校验和(16位) 源IP地址(32位) 目的IP地址(32位) 选项(32位) 20个字节 31
数据
9.5.2
ICMP头部结构
ICMP的头部结构比较复杂,主要包含消息类型 icmp_type,消息代码icmp_code、校验和icmp_cksum 等,不同的ICMP类型其他部分有不同的实现。 1.ICMP的头部结构 2.不同类型的ICMP请求

原始套接字(Raw Socket)解析

原始套接字(Raw Socket)解析
协议类型一共有四个
ETH_P_IP 0x800 只接收发往本机mac的ip类型的数据帧
ETH_P_ARP 0x806 只接受发往本机mac的arp类型的数据帧
ETH_P_ARP 0x8035 只接受发往本机mac的rarp类型的数据帧
ETH_P_ALL 0x3 接收发往本机mac的所有类型ip arp rarp的数据帧, 接收从本机发出的所有类型的数据帧.(混杂模式打开的情况下,会接收到非发往本地mac的数据帧)
ipHeader.checksum = 0;
ipHeader.sourceIP = inet_addr(&quot;localhost&quot;);
ipHeader.destIP = desIP;
//填充TCP报头
tcpHeader.th_dport = htons(desPort);
最后,进入udp输入例程 ...
ps:如果校验和出错的话,内核会直接丢弃该数据包的.而不会拷贝给sock_raw的套接字,因为校验和都出错了,数据肯定有问题的包括所有信息都没有意义了.
进一步分析他们的能力.
1. socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
addr_in.sin_addr.S_un.S_addr = inet_addr(desIP);
//填充IP报头
ipHeader.h_verlen = (4 &lt;&lt; 4 | sizeof(ipHeader) / sizeof(unsigned long));
// ipHeader.tos=0;
{
printf(&quot;send error!:%d\n&quot;, WSAGetLastError());

第6章 原始套接字

第6章   原始套接字

TCP
UDP OSPF
数据部分
IP 数据报
协议字段指出应将数据 部分交给哪一个进程
ICMP—1; IGMP—2;TCP—6;
UDP—17;OSPF--89
表1.4 ICMP报文类型
重定向: 0 5 1 2 3 8 9 10 11 0 0 0 0 1 12 13 14 15 16 17 18 0 1 0 0 0 0 0 0 对网络重定向 对主机重定向 对服务类型和网络重定向 对服务类型和主机重定向 请求回显(Ping 请求) 路由器通告 路由器请求 超时: 传输期间生存时间为 0(Traceroute) 在数据报组装期间生存时间为 0 参数问题: IP 首部错误(包括各种差错) 缺少必需的选项 时间戳请求 时间戳应答 信息请求(作废) 信息应答(作废) 地址掩码请求 地址掩码应答 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
6.3.1 IP数据报格式
固 定 部 分 20 字节 可变 部分
版 本 首部长度 标
服务类型 识 标志
总 长 度
片 偏 移 首 部 检 验 和
生存时间


源 地 址 目 的 地 址
可 选 字 段 (长 度 可 变)


上面是 IPv4 数据报的首部
typedef struct _IPHeader // 20字节的IP头 { UCHAR iphVerLen; // 版本号和头长度(各占4位) UCHAR ipTOS; // 服务类型 USHORT ipLength; // 封包总长度,即整个IP报的长度 USHORT ipID; // 封包标识,惟一标识发送 的每一个数据报 USHORT ipFlags; // 标志 UCHAR ipTTL; // 生存时间,就是TTL UCHAR ipProtocol; // 协议,可能是TCP、UDP、ICMP等 USHORT ipChecksum; // 校验和 ULONG ipSource; // 源IP地址 ULONG ipDestination; // 目标IP地址 } IPHeader, *PIPHeader;

原始套接字

原始套接字
telnet……)
传输层 (TCP、UDP)
网络互联层 (IP)
主机到网络 (网络接口层)
应用程序
13.1
原始套接字概述
标准套接字
TCP/UDP IP
网络 核心
原始套接字 用户空间 内核空间
ICMP
套接字与内核的访问关系
13.1
原始套接字概述
原始套接字能够提供以下3种标准套接字不具备的功能:
(0 – 40字节)
数据
全长 ip_len
分片偏移 ip_off
首部校验和 ip_cksum
13.3.1 IP首部结构
31
20 字节
最大 65535 字节
Linux中 struct ip 结构体说明:
struct ip {
#if __BYTE_ORDER == __LITTLE_ENDIAN
接收时间戳
发送时间戳
13.3.2ICMP首部结构
类型:13或14,时间戳请求和应答 代码:0
Linux中 struct icmp 结构体说明(BSD):
struct icmp {
u_int8_t
u_int8_t
icmp_type; icmp_code;
u_int16_t
icmp_cksum;
③ 如果IP以分片形式到达,则所有分片都已经接收到并重组后才传给原始 套接字 。
④ 内核不能识别的协议、格式等传给原始套接字,因此,可以使用原始套 接字实现自定义协议格式。
13.2.3
原始套接收报文
⑤ 如果收到的数据中的协议类型与自定义的原始套接字匹配,则将接收到
的数据复制到原始套接字接收缓冲区中。
② 原始套接字创建完成后,一般还需要指定套接字数据格式类型,使得 原始套接字可确定以从网络接收哪种格式的数据。

实验3_使用原始套接字实现ping的工作原理

实验3_使用原始套接字实现ping的工作原理
1. ICMP 协议与校验和的计算
互联网上的操作由路由器紧紧地监控着。当有异常发生时,具体事件通过 ICMP(Internet Control Message Protocol,网间控制报文协议)报道,如目的不可到达、TTL 超时等。这个协 议也用来测试互联网。
每个 ICMP 消息都封装在 IP 封包中,所以它使用 IP 寻址,图 2.1 所示为 ICMP 消息的格 式。
使用恰当的协议标志创建原始套接字之后,便可以在发送和接收调用中使用此套接字句柄 了。无论 IP_HDRINCL 选项是否设置,在原始套接字上接收到的数据中都将包含 IP 头。
– 27 –
Visual C++网络程序设计实例详解
2.1.2 Ping 程序运行原理 在网络层,除了 IP 协议之外,还有一些控制协议,如 ICMP、ARP、DHCP 等。下面主要 讲述 ICMP 协议,以及如何使用原始套接字编写 ICMP 程序(Ping 程序)。
unsigned short icmp_id;
// 用来惟一标识此请求的 ID 号,通常设置为进程 ID
unsigned short icmp_sequence; // 序列号
unsigned long icmp_timestamp; // 时间戳
} ICMP_HDR, *PICMP_HDR;
下面是完整的 Ping 程序代码,在配套光盘的 Ping 工程下。
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
// 如果为奇数,将最后一个字节扩展到双字,再累加到 cksum 中
if (size)

公开课 原始套接字编程

公开课 原始套接字编程

公开课原始套接字编程摘要:一、公开课主题介绍1.原始套接字编程简介2.公开课的主要内容二、原始套接字编程基本概念1.套接字的发展历史2.原始套接字与标准套接字的区别3.套接字编程的重要性三、套接字编程基础1.套接字类型及其区别2.套接字函数库及其功能3.套接字编程的基本流程四、原始套接字编程实例分析1.服务器端编程2.客户端编程3.通信过程演示五、原始套接字编程的应用领域1.网络通信2.数据传输3.网络安全六、总结与展望1.原始套接字编程的意义2.套接字编程在我国的发展现状3.未来套接字编程的发展趋势正文:一、公开课主题介绍本次公开课的主题是“原始套接字编程”。

在互联网技术高速发展的今天,套接字编程已经成为网络通信领域的重要技术之一。

原始套接字编程作为套接字编程的基础,对于深入理解网络通信原理具有重要意义。

本次公开课将详细讲解原始套接字编程的相关知识,帮助大家更好地掌握这一技术。

二、原始套接字编程基本概念套接字编程是一种网络编程技术,通过使用套接字(socket)实现不同计算机之间的数据传输。

套接字起源于UNIX 系统,经过多年的发展,已经成为各种操作系统都支持的一种标准编程接口。

原始套接字和标准套接字是套接字编程的两种主要形式,它们之间的主要区别在于对网络协议的支持程度。

原始套接字编程更接近于底层网络协议,能够实现更高效、更灵活的网络通信。

随着互联网的普及,套接字编程的应用领域越来越广泛,涵盖了网络通信、数据传输、网络安全等多个方面。

学习和掌握原始套接字编程,不仅能够提高个人的编程技能,还能为我国互联网产业的发展贡献力量。

三、套接字编程基础套接字编程的基础知识包括套接字类型、套接字函数库和套接字编程的基本流程。

套接字类型主要有流式套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAW)等,它们分别适用于不同的网络协议。

套接字函数库提供了大量用于实现套接字编程的函数,如socket、bind、listen、accept、send、recv 等。

网络通信编程 原始套接字程序设计

网络通信编程 原始套接字程序设计

➢SO_BROADCAST
选项值类型 bool
获取/设置 均可
Winsock版本 1+
说明
如果指定的套接字已经配置成收发广播数 据,对这个套接字选项进行查询,就会返 回TRUE。随SO_BROADCAST一起使用 setsockopt,便可在这个套接字上启用广播 通信功能。
对于非SOCK_STREAM类型的所有套接字
➢ 协议标志IPPROTO_UDP、IPPROTO_IP以及 IPPROTO_RAW均要求使用套接字选项IP_HDRINCL, 而该选项在上述平台下都是不支持的。
➢ Windows 2000提供了对IP_HDRINCL选项的支持,所以 能够处理IP头(IPPROTO_RAW)、TCP头(IPPROTO_TCP) 以及UDP头(IPPROTO_UDP)。
A
9
选项级别: 协议的层次对应选项级别 应用层:SOL_SOCKET 传输层:IPPROTO_TCP、IPPROTO_UDP 网络层:IPPROTO_IP 不同级别属性不同,同一级别的不同协议的属
性不同,因此必须指定level参数 例:Int nTime=2*1000
setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&n Time,sizeof(nTime))
第四章
原始套接字
A
1
内容提要
▪ 1.使用原始套接字 ▪ 2.套接字选项 ▪ 3.ICMP编程 ▪ 4.使用IP头包含选项 ▪ 5.网络嗅探器实例
A
2
1.使用原始套接字
▪ 利用原始套接字(Raw Socket),可访问底层传 输协议。
▪ 原始套接字(Raw Socket))与标准套接字区别

原始套接字与网络检测技术

原始套接字与网络检测技术
原始套接字与网络检 测技术
原始套接字
原始套接字是允许访问底层传输协议的一 种套接字
原始套接字有两种类型:
在IP头中使用预定义的协议,如ICMP 在IP头中使用自定义的协议
创建原始套接字
使用函数socket()或WSASocket()
例:
SOCKET sRaw=socket(AF_INET,SOCK_RAW,IPPRPTP_ICMP);
互联网的操作由路由器监控着,遇有异常 发生,具体事件通过该协议报告。
ICMP报文
ICMP报文可分为两大类:差错报告报文和查询 报文
报文结构:
类型(8b) 代码(8b) 校验和(16b) 内容(取决于类型和代码)
ICMP报文与IP报文的关系
ICMP报文
IP首部
ICMP报文
ICMP报文的类型
原理:由本地发送UDP封包到目的地址, 递加TTL值。初始情况下,TTL值为1,这 个UDP封包到达第一个路由器后将中止。 这个终止会促使路由器产生一个ICMP超时 封包。然后TTL值加1,再发送这个UDP封 包。收集每个ICMP消息便可知道封包所经 过的路由器。如果最终到达目的地址,多 半会返回ICMP端口不可达消息,因为没有 进程在等待这个封包。
unsigned char icmp_code; //代码 unsigned short icmp_checksum; //校验和 unsigned short icmp_id; //ID号 unsigned short icmp_sequence; //序列号 unsigned long icmp_timestamp; //时间戳 } ICMP_HDR,*PICMP_H利用。因此,仅administrator组的成员能够 创建SOCK_RAW类型的套接字。任何人在NT下都 可以创建原始套接字,但是没有administrator权限 的用户不能用它做任何事情,因为bind函数将会失 败。

信息安全系统实践第十一次作业原始套接字、

信息安全系统实践第十一次作业原始套接字、

四川大学计算机学院、软件学院
实验报告
学号:姓名:专业:__软件工程__ 班级:第 12 周
{
tcph=(struct tcphdr*)(buffer+sizeof(struct ether_header)+sizeof(struct ip));
printf("Sourport:%d\n",ntohs(tcph->source));
printf("Destport :%d\n",ntohs(tcph->dest));
}
}
}
}
这里主要修改的地方是:
1、原代码问题:在输出ip那部分需要利用inet_ntop函数,不然程序运行出问题。

2、加入了TCP头部解封,输出源端口和目的端口,当然还要把相应的头文件加入。

其实只要把上面这程序和这次的syn flood结合起来再做点修
*((u_char*)&oddbyte)=*(u_char*)ptr;
sum+=oddbyte;
}
sum = (sum>>16)+(sum & 0xffff);
sum = sum + (sum>>16);
answer=(short)~sum;
return(answer);
}
下面让我们看一下运行效果:
运行syn flood程序,使用不同的伪装IP攻击:
然后检验结果:
数据记录
和计算
结论
通过(结果)。

原始套接字

原始套接字

原始套接字链路层网络编程技术收藏实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM)。

而这些数据包都是由系统提供的协议栈实现,用户只需要填充应用层报文即可,由系统完成底层报文头的填充并发送。

然而在某些情况下需要执行更底层的操作,比如修改报文头、避开系统协议栈等。

这个时候就需要使用其他的方式来实现。

一原始套接字原始套接字(SOCK_RAW)是一种不同于SOCK_STREAM、SOCK_DGRAM的套接字,它实现于系统核心。

然而,原始套接字能做什么呢?首先来说,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

总体来说,SOCK_RAW可以处理普通的网络报文之外,还可以处理一些特殊协议报文以及操作IP层及其以上的数据。

既然SOCK_RAW有以上特性,所以在某些处理流程上它区别于普通套接字。

·若设置IP_HDRINCL选项,SOCK_RAW可以操作IP头数据(也就是用户需用填充IP头及其以上的payload);否则SOCK_RAW无法操作IP头数据·端口对于SOCK_RAW而言没有任何意义·如果使用bind函数绑定本地IP,那么如果IP_HDRINCL未设置,则用此IP填充源IP地址;若不调用bind则将源IP地址设置为外出接口的主IP地址·如果使用connect函数设置目标IP,则可以使用send或者write函数发送报文,而不需要使用sendto函数·内核处理流程:·接收到的TCP、UDP分组不会传递给任何SOCK_RAW· ICMP、IGMP报文分组传递给SOCK_RAW·内核不识别的IP报文传递给SOCK_RAW· SOCK_RAW是否接收报文:· Protocol指定类型需要匹配,否则不传递给该SOCK_RAW·如果使用bind函数绑定了源IP,则报文目的IP必须和绑定的IP匹配,否则不传递给该SOCK_RAW·如果使用connect函数绑定了目的IP,则报文源IP必须和指定的IP匹配,否则不传递给该SOCK_RAW综上所述,原始套接字处理的只是IP层及其以上的数据,比如实现SYN FLOOD攻击、处理PING报文等。

网络应用程序的设计第3章 UDP套接字与原始套接字的编程.ppt

网络应用程序的设计第3章 UDP套接字与原始套接字的编程.ppt

第3章 UDP套接字与原始套接字的编程
在前面的章节中,已经介绍了基于TCP套接字编程的 函数调用模型,比较TCP和UDP编程模型可以看出,UDP 协议不需要事先在客户机、服务器程序之间建立连接。服 务 器 端 在 调 用 socket 函 数 生 成 一 个 UDP 套 接 字 后 , 利 用 bind函数将套接字与本地IP、端口号绑定,然后,服务器 端调用recvfrom函数等待接收由客户端发送来的数据。客 户机首先调用socket函数创建一个UDP套接字,然后利用 sendto函数将请求包发送至服务器端;服务器端收到请求 包后,根据请求进行处理,调用sendto函数将处理结果作 为应答数据发送给客户机。客户机调用recvfrom函数接收 服务器端发送来的应答数据。当通信结束后,客户机调用 close函数关闭UDP套接字,而服务器端可以保留已建立的 UDP套接字继续与其他客户机进行数据通信。
第3章 UDP套接字与原始套接字的编程
第3章 UDP套接字与原始套接字的编程
3.1 概述 3.2 UDP套接字编程 3.3 连接UDP套接字的功能 3.4 UDP编程中的错误检测及处理方法 3.5 UDP套接字在OICQ服务中的应用 3.6 原始套接字 3.7 服务器编程模型 习题
第3章 UDP套接字与原始套接字的编程
第3章 UDP套接字与原始套接字的编程
UDP套接字在通信中发送和接收的数据是以数据 报为单位的。当应用程序调用函数sendto发送数据时, 首先应将数据封装生成一个UDP数据报,然后发送; 当应用程序调用函数recvfrom接收数据时。UDP协议将 返回一个完整的UDP数据报数据内容。在使用UDP套 接字进行编程时,我们必须注意以下几个问题:
3.1 概述
Internet 协 议 簇 支 持 一 个 面 向 无 连 接 的 传 输 协 议 用户数据报协议(UDP,User Datagram Protocol)。UDP 协议向应用程序提供了一种发送经过封装的IP数据报 的方法,而且不需要在发送方和接收方之间建立连接 就可以进行数据报通信。

【VIP专享】Linux网络编程:原始套接字的魔力【下】

【VIP专享】Linux网络编程:原始套接字的魔力【下】

Linux网络编程:原始套接字的魔力【下】星期四, 8月 23 2012, 10:47 下午可以接收链路层MAC帧的原始套接字前面我们介绍过了通过原始套接字socket(AF_INET, SOCK_RAW, protocol)我们可以直接实现自行构造整个IP报文,然后对其收发。

提醒一点,在用这种方式构造原始IP报文时,第三个参数protocol不能用IPPROTO_IP,这样会让系统疑惑,不知道该用什么协议来伺候你了。

今天我们介绍原始套接字的另一种用法:直接从链路层收发数据帧,听起来好像很神奇的样子。

在Linux系统中要从链路层(MAC)直接收发数帧,比较普遍的做法就是用libpcap和libnet两个动态库来实现。

但今天我们就要用原始套接字来实现这个功能。

这里的2字节帧类型用来指示该数据帧所承载的上层协议是IP、ARP或其他。

为了实现直接从链路层收发数据帧,我们要用到原始套接字的如下形式:socket(PF_PACKET, type, protocol)1、其中type字段可取SOCK_RAW或SOCK_DGRAM。

它们两个都使用一种与设备无关的标准物理层地址结构struct sockaddr_ll{},但具体操作的报文格式不同:SOCK_RAW:直接向网络硬件驱动程序发送(或从网络硬件驱动程序接收)没有任何处理的完整数据报文(包括物理帧的帧头),这就要求我们必须了解对应设备的物理帧帧头结构,才能正确地装载和分析报文。

也就是说我们用这种套接字从网卡驱动上收上来的报文包含了MAC头部,如果我们要用这种形式的套接字直接向网卡发送数据帧,那么我们必须自己组装我们MAC头部。

这正符合我们的需求。

SOCK_DGRAM:这种类型的套接字对于收到的数据报文的物理帧帧头会被系统自动去掉,然后再将其往协议栈上层传递;同样地,在发送时数据时,系统将会根据sockaddr_ll结构中的目的地址信息为数据报文添加一个合适的MAC帧头。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

UI原始套接字(protosockets)库
2016-03-05 11:08:17| 分类:TCP/UDP |
详细说明:
原始套接字(protosocket)为uIP提供了一个与传统BSD套接字接口类似的接口。

不同于为传统uIP事件驱动接口写的程序,为原始套接字(protosocket)接口写的程序是顺序方式执行的,并且无需以明确的状态机方式实现。

原始套接字(protosocket)只能用于TCP连接。

原始套接字(protosocket)库使用"原始线程(protothreads)"来提供顺序控制流。

这使得原始套接字在内存方面变得轻量型,但也同时意味着原始套接字继承了"原始线程"的功能限制。

每个原始套接字只能生存于单个函数中,自动变量(栈变量)不能跨原始套接字函数调用存在。

注意:
由于原始套接字库使用的是"原始线程(protothreads)",在调用原始套接字库函数时,局部变量并不总能得到保存.所以这里建议局部变量的使用要十分小心。

原始套接字库提供了一些无需处理重传和回应的发送数据函数,和一些无需对被分解成多个TCP段的数据进行处理的读取数据函数。

由于每个原始套接字都作为一个“原始线程”来运行,应在使用原始套接字的函数起始处通过调用PSOCK_BEGIN() 的方式启用原始套接字。

与之类似,原始套接字可以通过调用PSOCK_EXIT()结束掉。

相关文件:
psock.h 原始套接字库头文件。

相关结构体:
struct psock_bufstruct psock 代表一个原始套接字。

#define PSOCK_INIT(psock, buffer, buffersize) 初始化一个原始套接字。

#define PSOCK_BEGIN(psock) 在一个函数中启用一个原始套接字的原始线程。

#define PSOCK_SEND(psock, data, datalen) 发送数据。

#define PSOCK_SEND_STR(psock, str) 发送一个以零结尾的字符串。

#define PSOCK_GENERATOR_SEND(psock, generator, arg) 通过函数(generator)产生数据并发送出去。

#define PSOCK_CLOSE(psock) 关闭一个原始套接字。

#define PSOCK_READBUF(psock) 读数据直到缓冲区满。

#define PSOCK_READTO(psock, c) 读数据到字符c.
#define PSOCK_DATALEN(psock) 获得上次读到的数据长度。

#define PSOCK_EXIT(psock) 退出原始套接字的原始线程。

#define PSOCK_CLOSE_EXIT(psock) 关闭一个原始套接字,并退出其原始线程。

#define PSOCK_END(psock) 声明一个原始套接字的原始线程的结尾。

#define PSOCK_NEWDATA(psock) 查明是否有数据到达原始套接字。

#define PSOCK_WAIT_UNTIL(psock, condition) 等待,直到条件(condition)为真。

#define PSOCK_WAIT_THREAD(psock, condition) PT_WAIT_THREAD(&((psock)->pt), (condition))
u16_t psock_datalen(struct psock *psock) char psock_newdata(psock * s)
参数:psock 是(struct psock *)指向要启用的原始套接字的结构体指针。

1. #define PSOCK_BEGIN(psock)
启用一个原始套接字的原始线程。

此宏启用一个原始套接字关联的原始线程,必须在调用其它原始套接字函数之前出现。

2. #define PSOCK_CLOSE(psock)
此宏用于关闭一个原始套接字,只能用于此原始套接字生存的原始线程中.
3. #define PSOCK_CLOSE_EXIT(psock)
此宏用于关闭一个原始套接字,并退出原始套接字生存的线程.
4. #define PSOCK_DATALEN(psock)
返回之前通过PSOCK_READTO() 或PSOCK_READ()读到的数据长度.
5. #define PSOCK_END(psock)
此宏用于声明原始套接字的原始线程结束.常于PSOCK_BEGIN(psock)配合使用.
6. #define PSOCK_EXIT(psock)
此宏用于终止原始套接字的原始线程,必须与PSOCK_CLOSE一起使用.
也可以直接使用PSOCK_CLOSE_EXIT();
7. #define PSOCK_GENERATOR_SEND(psock,generator,arg)
通过函数产生数据并发送.
generator 指向产生数据的函数的指针.
arg 要传给函数的参数.
使宏用于通过函数产生数据,并通过原始套接字发送,它可以用于动态产生数据并传输,而不必先将产生的数据存入缓冲区.此函数减小了缓冲区内存的开销,产生器函数由应用程序实现,使用时要将
函数的指针作为一个参数传给宏,产生器函数应该将产生的数据直接存放在uip_appdata缓冲区中,并返回产生数据的长度。

数据每一次发送时,原始套接字层会调用产生器函数,并且如果出现重发的情况,则也会调用一次产生器函数,也就是说重发的值并非第一次产生器函数调用时的值。

8. #define PSOCK_INIT(psock ,buffer,buffersize)
这个宏初始化一个原始套接字,它必须在使用套接字之前得到调用. 此宏还规定了套接字的输入缓冲区.
参数:
buffer (char * ) 指向原始套接字的输入缓冲区的指针.
buffersize (unsigned int) 输入缓冲区的大小.
9. #define PSOCK_NEWDATA(psock)
此宏用于查明是否有数据到达套接字。

它常和PSOCK_WAIT_UNTIL() 连用,查看套接字上是否有新的数据到达。

10. #define PSOCK_READBUF(psock)
读数据直到缓冲区满。

此宏会阻塞数据等待,把数据读入由PSOCK_INIT()指定的输入缓冲区。

读数据操作会进行到缓冲区满为止。

11. #define PSOCK_READTO(psock,c)
读数据直到某字符出现。

此宏会阻塞数据等待并开始读取数据到由PSOCK_INIT()指定的输入缓冲区,数据读取会一直持续到由参数c指定的字符出现为止。

c (char )用于指示停止读取数据的字符。

12. #define PSOCK_SEND(psock,data,datalen)
发送数据。

此宏通过原始套接字发送数据。

原始套接字阻塞原始线程,直到所有的数据发送完毕,并且已经被完程TCP终端接收。

data (char *) 指向要发送的数据的指针。

datalen (unsigned int)要发送的数据长度。

13. #define PSOCK_SEND_STR(psock,str)
发送一个以零结尾的字符串。

str 要发送的字符串。

14. #define PSOCK_WAIT_UNTIL(psock,condition) 等待直接条件为真。

阻塞原始线程,直到条件为真。

宏PSOCK_NEWDATA()可以用来检查此宏等待时有没有新数据到来。

此宏的典型用法如下:
1. PT_THREAD(thread(struct psock *s, struct timer *t))
2. {
3. PSOCK_BEGIN(s);
4.
5. PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t));
6.
7. if(PSOCK_NEWDATA(s)) {
8. PSOCK_READTO(s, '\n');
9. } else {
10. handle_timed_out(s);
11. }
12.
13. PSOCK_END(s);
14. }。

相关文档
最新文档