UIP中文文档第五 原始套接字_protosockets_库
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。
socket套接字的概念
socket套接字的概念套接字(socket)是网络编程中的一个重要概念,用于在不同节点之间建立通信连接,实现数据的传输和通信的实时交互。
下面我们从以下几个方面来介绍套接字的概念及其作用。
一、套接字的定义和作用套接字是一种抽象数据类型,用于表示一个网络通信的端点,可以理解为给应用程序提供了一种接口,使其能够通过网络与其他应用程序进行通信。
套接字是应用层与传输层间交互的一种方式,它提供了一种可靠的、面向连接的、双向数据传输的网络通信服务。
二、套接字的类型由于套接字在不同情况下有不同的用途,因此其类型也有所差异。
在Unix系统中,套接字一般分为以下几种类型:1. 流式套接字(SOCK_STREAM):基于TCP协议,提供面向连接的可靠数据传输服务。
它是一种面向字节流的套接字类型,可用于实现长连接。
2. 数据报套接字(SOCK_DGRAM):基于UDP协议,提供无连接的、不可靠的数据传输服务。
它是一种面向数据包的套接字类型,可用于实现短连接或者需要时间敏感的场景。
3. 原始套接字(SOCK_RAW):提供完全自由的数据包传输服务,在传输层及以下各层的数据包都可以被访问到。
它可以用于网络协议的实现及测试。
4. 信号套接字(SOCK_SEQPACKET):提供可靠的面向连接的数据传输服务,接收方只能够依次按短的数据包与发送方通信,保证数据的有序性。
三、套接字的编程接口套接字编程接口提供了开发人员在应用程序中使用网络通信技术的一套标准API,其主要包括以下几个方面:1. 套接字的创建和销毁:通过socket函数创建套接字,然后使用close 函数释放套接字资源。
2. 套接字的命名:使用bind函数将套接字与本地的IP地址和端口号进行绑定。
3. 套接字的连接:使用connect函数将套接字连接到远程主机的IP地址和端口号。
4. 数据的读取和写入:使用read和write函数进行数据的收发操作。
5. 套接字的监听:使用listen函数将套接字置于被动监听状态,等待远程客户端的连接请求。
uIP原始套接字
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) 发送数据。
套接字(socket、tcp、udp、原始)
TCPsocket:获得套接字的详细信息:获得本地地址结构 int getsockname ( SOCKET s, struct sockaddr FAR* name, int FAR* namelen ); 获得对端地址结构 int getpeername ( SOCKET s, struct sockaddr FAR* name, int FAR* namelen ); listen():指示套接字等待连接 int listen ( SOCKET s, int backlog ); 返回值 成功:返回0 失败:返回SOCKET_ERROR 。accept():接受客户端连接 SOCKET accept ( SOCKET s, struct sockaddr * addr, int FAR* addrlen ); 返回值 成功:返回新套接字的描述符 失败:返回INVALID_SOCKET。
hostent是host entry的缩写,该结构记录主机的信息,包括主机名、别名、地址类型、地址长度和地址列表。 hostent的定义: struct hostent { char *h_name; char **h_aliaslength; char **h_addr_list; }; 。
利用原始套接字实现Traceroute程序 :实现原理: 方法一: 发送UDP数据包,连续递增TTL值; TTL值每一次“超时”,返回一条ICMP消息; 需创建两个套接字,一个为UDP套接字,一个为ICMP套接字; UDP套接字的TTL值使用setsockopt函数设置IP_TTL套接字选项。 方法二: 发送ICMP数据包到目的地址,连续递增TTL值; TTL值每一次“超时”,返回一条ICMP消息。
套接字所用的类型
题目:套接字所用的类型摘要:本文探讨了在网络编程中使用的套接字类型,重点介绍了流套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAW)三种类型。
文章解释了每种类型的套接字如何工作以及它们在网络通信中的优缺点。
一、引言套接字(Socket)是计算机网络编程中的重要概念,它们被用来实现网络通信的不同层和模型中的数据交互和收发。
套接字类型决定了数据在网络中的传输方式,不同的套接字类型适用于不同的应用场景。
本文将深入探讨网络编程中常见的套接字类型以及它们的适用范围和特点。
二、流套接字(SOCK_STREAM)流套接字是一种面向连接的套接字类型,通常用于TCP协议。
它提供了一种可靠的、双向的、基于字节流的通信方式。
流套接字确保数据的按序交付和错误控制。
因此,它是实现基于TCP的应用层协议(如HTTP、SMTP等)的理想选择。
优点:1. 可靠的数据传输:通过确认机制、重传丢失的数据包和流量控制来确保数据的可靠传输。
2. 按序交付:确保数据包的顺序与发送时的顺序一致。
3. 错误控制:检测并处理数据传输过程中的错误。
缺点:1. 较高的开销:为确保可靠传输,TCP协议需要维护连接状态,这可能导致较高的开销。
2. 可能产生拥塞:在网络拥堵的情况下,流套接字的性能可能受到影响。
三、数据报套接字(SOCK_DGRAM)数据报套接字是一种无连接的套接字类型,通常用于UDP协议。
它提供了一种不可靠的、无连接的通信方式,适用于对实时性要求较高或能容忍数据丢失的应用场景。
数据报套接字以独立的数据包形式发送数据,不保证数据的按序交付或可靠性。
优点:1. 低开销:UDP协议开销小,适合于传输较少数据的场景。
2. 实时性:无需建立连接,传输延迟低,适合于实时应用场景如语音通话或视频流。
3. 灵活性:允许发送不同大小的数据包,且数据包独立传输。
缺点:1. 不可靠的数据传输:不保证数据包的可靠传输,可能会丢失或重复接收数据包。
原始套接字(Raw Socket)解析
2. socket(PF_PACKET, SOCK_RAW, htons(x));
这个套接字比较强大,创建这种套接字可以监听网卡上的所有数据帧.从上面看就是20+20+8+100.最后一个以太网crc从来都不算进来的,因为内核已经判断过了,对程序来说没有任何意义了.
==SOCKET_ERROR)
{
printf("setsockopt IP_HDRINCL error!\n");
return false;
}
nTimeOver = 1000;
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*) &nTimeOver, sizeof
tcpHeader.th_sport = htons(SOURCE_PORT); //源端口号
tcpHeader.th_seq = htonl(0x12345678);
tcpHeader.th_ack = 0;
tcpHeader.th_lenres = (sizeof(tcpHeader) / 4 << 4 | 0);
3. socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)),这个一般用于抓包程序。
总结使用方法:
1.只想收到发往本机某种协议的ip数据包的话用第一种就足够了
2. 更多的详细的内容请使用第二种.包括ETH_P_ALL参数和混杂模式都可以使它的能力不断的加强.
理解一下SOCK_RAW的原理, 比如网卡收到了一个 14+20+8+100+4 的udp的以太网数据帧.
原始套接字
传输层 (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
原始套接收报文
⑤ 如果收到的数据中的协议类型与自定义的原始套接字匹配,则将接收到
的数据复制到原始套接字接收缓冲区中。
② 原始套接字创建完成后,一般还需要指定套接字数据格式类型,使得 原始套接字可确定以从网络接收哪种格式的数据。
网络程序设计 原始套接字
17:03:48
7
ICMP编程
ICMP协议 PING程序分析 TRACEROUTE程序分析
17:03:48
8
Internet控制消息协议
Internet控制消息协议(ICMP)主要用于在主 机间传递简短消息的一种机制。 ICMP 报文的种类有两种,即 ICMP 差错报告 报文和 ICMP 询问报文。 ICMP协议采用IP定址机制,因为它本身就是封 装在IP数据报内的一种协议。
17:03:48 24
UDP头简单。长度仅为8个字节,而且只包含 了四个字段,格式如图所示。
源端口(16位) UDP长度(16位) 目标端口(16位) UDP校验和(16位)
由于UDP是一种不能保证数据可靠传输的协议,所 UDP 以校验和的计算是可选的。 UDP校验和除覆盖了UDP头之外,还同时覆盖了实 际的数据,此外还包括IP头的一部分。
17:03:48 14
编写Ping程序的步骤: 1) 创建类型为SOCK_RAW的套接字,同时设定协议 IPPROTO_ICMP。 2) 创建并初始化ICMP包(包括ICMP头和数据)。 3) 调用sendto或WSASendto,将ICMP请求发给远程主 机。 4) 调用recvfrom或WSARecvfrom接收任何ICMP响应 包。 5)解析收到的ICMP响应包。
Description Echo Response,(CODE=0) Destination Unreachable (CODE=0) Source Quench Redirection Echo Request,(CODE=0) Router Advertisement Router Solicitation Datagram Timeout(TTL=0)(CODE =0) Datagram Parameter Error Timestamp Request Timestamp Response Information Request(out of date) Information Response(out of date) Address Mask Request Address Mask Response 可达性测试 报告无法找到目的 抑制源站发送 路由已发生改变 路由器间协调 过长路由(超时) 报文格式错 时间同步 作废 掩码维护
套接字与文件描述符
套接字与⽂件描述符TCP服务器端:int socket(int domain , int type , int protocol)domain(协议族):常⽤的协议族便是IPV4(PF_INET), IPV6(PF_INET6),本地通信协议的UNIX族(PF_LOCAL)type:数据传输类型;典型数据传输类型:⾯向连接的套接字(SOCK_STREAM),⾯向消息的套接字(SOCK_DGRAM)protocal:具体协议;返回套接字⽂件描述符,在linux中,不区分套接字和⽂件,统⼀⽤⽂件描述符来描述;TCP与UDP的区别:1. TCP是⾯向连接,UDP是⽆连接的传输2. TCP保证了数据传输的正确和有序,⽽UDP不保证3. TCP数据传输是⽆边界的,也就是流模式(待查),UDP传输是有边界的,采⽤数据报模式(待查)4. TCP需要更多的系统资源int bind(int sockfd , const struct sockaddr* servaddr , socklen_t addrlen);给套接字分配IP地址和端⼝号,将套接字和相应的IP地址和端⼝号绑定,失败返回-1;当没有给套接字绑定IP地址和端⼝号(端⼝号指定为0)时,bind函数被调⽤时会分配⼀个临时端⼝号与套接字进⾏绑定,但是IP地址会当TCP连接建⽴(客户端⽬的IP地址)或者在此套接字上发送UDP数据报时才会绑定IP地址;当IP地址指定为通配int listen(int fd , int backlog)将套接字变为可接受连接状态;内核为监听套接字维护两个队列,⼀个是未完成连接队列,该队列中的每⼀项为客户端发送的SYN字节,另⼀个是已完成连接队列,存储已完成连接的客户端套接字,当accept调⽤时,就从该队列的队头返回,当该队int accept(int sockfd , struct sockaddr* addr , socklen_t* addrlen) ;接受连接,返回⼀个全新的套接字,称为“已连接套接字”,由内核创建的⼀个全新的套接字,⾃动完成与对应的客户端套接字的连接(三路握⼿),由这个全新的套接字与客户端套接字进⾏通信TCP客户端:int connect(int sockfd , struct sockaddr* servaddr, socklen_t addrlen)connect函数完成两件事,如果套接字没有被绑定IP地址和端⼝号,内核会分配⼀个临时端⼝号,并与套接字进⾏绑定。
网络编程--Socket(套接字)
⽹络编程--Socket(套接字)⽹络编程⽹络编程的⽬的就是指直接或间接地通过⽹络协议与其他计算机进⾏通讯。
⽹络编程中有两个主要的问题,⼀个是如何准确的定位⽹络上⼀台或多台主机,另⼀个就是找到主机后如何可靠⾼效的进⾏数据传输。
在TCP/IP协议中IP层主要负责⽹络主机的定位,数据传输的路由,由IP地址可以唯⼀地确定Internet上的⼀台主机。
⽽TCP层则提供⾯向应⽤的可靠的或⾮可靠的数据传输机制,这是⽹络编程的主要对象,⼀般不需要关⼼IP层是如何处理数据的。
⽬前较为流⾏的⽹络编程模型是客户机/服务器(C/S)结构。
即通信双⽅⼀⽅作为服务器等待客户提出请求并予以响应。
客户则在需要服务时向服务器提出申请。
服务器⼀般作为守护进程始终运⾏,监听⽹络端⼝,⼀旦有客户请求,就会启动⼀个服务进程来响应该客户,同时⾃⼰继续监听服务端⼝,使后来的客户也能及时得到服务。
在Internet上IP地址和主机名是⼀⼀对应的,通过域名解析可以由主机名得到机器的IP,由于机器名更接近⾃然语⾔,容易记忆,所以使⽤⽐IP地址⼴泛,但是对机器⽽⾔只有IP地址才是有效的标识符。
通常⼀台主机上总是有很多个进程需要⽹络资源进⾏⽹络通讯。
⽹络通讯的对象准确的讲不是主机,⽽应该是主机中运⾏的进程。
这时候光有主机名或IP地址来标识这么多个进程显然是不够的。
端⼝号就是为了在⼀台主机上提供更多的⽹络资源⽽采取得⼀种⼿段,也是TCP层提供的⼀种机制。
只有通过主机名或IP地址和端⼝号的组合才能唯⼀的确定⽹络通讯中的对象:进程。
套接字所谓socket通常也称作"套接字",⽤于描述IP地址和端⼝,是⼀个通信链的句柄。
应⽤程序通常通过"套接字"向⽹络发出请求或者应答⽹络请求。
套接字可以根据通信性质分类,这种性质对于⽤户是可见的。
应⽤程序⼀般仅在同⼀类的套接字间进⾏通信。
不过只要底层的通信协议允许,不同类型的套接字间也照样可以通信。
什么是套接字Socket详解
什么是套接字Socket详解套接字(Socket)起初来源于UNIX,是加利福尼亚大学Berkeley分校开发的UNIX操作系统下的网络通信接口。
随着UNIX操作系统的广泛使用,Socket亦当之无愧的成为了最流行的网络通信程序接口之一。
90年代初期,由SunMicrosystems,JSB.CO,FTPSoftware,Microdyne和Microsoft等几家公司联合制定了一套Windows下套接字编程的规范,称为WindowsSockets规范,初步实现了Windows下的Sockets接口程序的标准化,并于1992年推出了WindowsSocketsV1.0版,次年发表了其2.0版,IBM发行的TCP/IPV2.1forDOS就是其代表,它还提供了WindowsSockets 的应用程序接口(API)。
Microsoft的WindowsSocketsAPI是Windows下的网络应用程序接口,为了适用于Windows下的消息机制和异步的I/O 选择操作,WindowsSocketsAPI在功能上扩充了将近20个函数,其中扩充的部分均冠以前缀WSA (WindowsSocketsAsynchronous),如WSAStartup、WSAClean 等,充分体现了Widnows的优越性。
此外,WindowsSocketsAPI有16位版和32位版两种,16位版是单进程的,32位版则提供了多线程下的安全保护。
本文将浅解Windows下的Sockets编程的机理,旨在抛砖引玉。
一并说明WindowsSockets编程的重要性!一、WindowsSockets简介套接字是网络通信的基本构件,提供了不同主机间进程双向通信的端点,如同电话,只有当一方拨通另一方时,双方方能建立对话,而套接字正好比双方的电话。
通过Sockets编程,程序可以跳过复杂的网络底层协议和结构,直接编制与平台无关的应用程序。
随着Internet的广泛应用,Sockets已逐渐成为网络编程的通用接口。
socket套接字描述符 分配规则-概述说明以及解释
socket套接字描述符分配规则-概述说明以及解释1.引言1.1 概述概述:在计算机网络中,套接字是实现网络通信的一种机制,它允许不同的计算机之间通过网络进行数据传输和交互。
套接字描述符是唯一标识一个套接字的数字,它在程序中起到关键的作用。
对于开发人员来说,正确地分配和使用套接字描述符是确保网络通信稳定和高效的重要一环。
本文将深入探讨socket套接字描述符的分配规则,并提供一些使用注意事项。
首先,我们将对socket套接字描述符的定义进行详细介绍,以便读者对其有一个清晰的认识。
接着,我们将重点讨论socket套接字描述符的分配规则,包括其分配的原则和流程。
此外,我们还将提供一些使用套接字描述符时需要注意的事项,以避免可能出现的错误和问题。
总之,了解并遵守socket套接字描述符的分配规则,能够更好地优化网络通信,提升系统的性能和稳定性。
本文的目的是向读者介绍socket 套接字描述符的重要性,强调合理分配socket套接字描述符的必要性,并提出进一步研究socket套接字描述符分配规则的建议。
通过对这些内容的深入了解,读者将能够更好地利用socket套接字描述符,并在实际网络应用中取得更好的效果。
1.2 文章结构文章结构是指将一篇长文按照一定的组织方式进行划分,使读者能够更加清晰地理解文章的内容和逻辑结构。
文章结构的设计直接影响到读者对文章的理解和阅读效果。
本文的结构分为引言、正文和结论三个部分。
引言部分主要包括概述、文章结构和目的三个方面。
概述部分介绍了本文要讨论的主题-socket套接字描述符,并简要介绍了它的意义和作用。
文章结构部分则对整篇文章的结构进行了总体的概述,让读者对文章的组织有一个清晰的认识。
目的部分明确了本文的写作目的,即探讨socket 套接字描述符的分配规则以及使用注意事项。
正文部分是重点部分,包括几个小节,主要介绍了socket套接字描述符的定义、分配规则以及使用注意事项。
原始套接字
原始套接字链路层网络编程技术收藏实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(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报文等。
套接字的基本结构(linux)
套接字的基本结构(linux)套接字的基本结构================(1) socket()⽤于在套接字⽂件系统(sockfs)中创建套接字⽂件.套接字⽂件的操作表为socket_file_ops, 它与⽂件套接字操作表(proto_ops)相交互,⽂件套接字操作表与⽹络套接字操作表(proto)相交互.(2) ⽂件套接字⽤socket结构描述, ⽹络套接字⽤sock结构描述.⽂件套接字存在于inode的u.socket_i单元之中并且指向相应的⽹络套接字.(3) 套接字的协议族确定了对套接字的创建操作, 套接字的类型确定了对⽂件套接字的操作,套接字的协议确定了对⽹络套接字的操作. 对PF_INET协议族来说,SOCK_STREAM类型的⽂件套接字操作表为inet_stream_ops, ⽹络套接字操作表为tcp_prot. SOCK_DGRAM类型的⽂件套接字操作表为inet_dgram_ops, ⽹络套接字操作表为udp_prot. SOCK_RAW类型的⽂件套接字操作表为inet_dgram_ops, ⽹络套接字操作表为raw_prot.; net/ipv4/af_inet.c:struct net_proto_family inet_family_ops = {PF_INET,inet_create};static int inet_create(struct socket *sock, int protocol){struct sock *sk;struct proto *prot;sock->state = SS_UNCONNECTED;sk = sk_alloc(PF_INET, GFP_KERNEL, 1);if (sk == NULL)goto do_oom;switch (sock->type) {case SOCK_STREAM:if (protocol && protocol != IPPROTO_TCP)goto free_and_noproto;protocol = IPPROTO_TCP;prot = &tcp_prot;sock->ops = &inet_stream_ops;break;case SOCK_SEQPACKET:goto free_and_badtype;case SOCK_DGRAM:if (protocol && protocol != IPPROTO_UDP)goto free_and_noproto;protocol = IPPROTO_UDP;sk->no_check = UDP_CSUM_DEFAULT;prot=&udp_prot;sock->ops = &inet_dgram_ops;break;case SOCK_RAW:if (!capable(CAP_NET_RAW))goto free_and_badperm;if (!protocol)goto free_and_noproto;prot = &raw_prot;sk->reuse = 1;sk->num = protocol;sock->ops = &inet_dgram_ops;if (protocol == IPPROTO_RAW)sk->protinfo.af_inet.hdrincl = 1; 由⽤户创建IP包头break;default:goto free_and_badtype;}if (ipv4_config.no_pmtu_disc)sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT; elsesk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT; sock_init_data(sock,sk);sk->destruct = inet_sock_destruct;sk->zapped = 0;sk->family = PF_INET;sk->protocol = protocol;sk->prot = prot;sk->backlog_rcv = prot->backlog_rcv;sk->protinfo.af_inet.ttl=sysctl_ip_default_ttl;sk->protinfo.af_inet.mc_loop=1;sk->protinfo.af_inet.mc_ttl=1;sk->protinfo.af_inet.mc_index=0;sk->protinfo.af_inet.mc_list=NULL;#ifdef INET_REFCNT_DEBUGatomic_inc(&inet_sock_nr);#endifif (sk->num) {/* It assumes that any protocol which allows* the user to assign a number at socket* creation time automatically* shares.*/sk->sport = htons(sk->num);/* Add to protocol hash chains. */sk->prot->hash(sk);}if (sk->prot->init) {int err = sk->prot->init(sk);if (err != 0) {inet_sock_release(sk);return(err);}}return(0);free_and_badtype:sk_free(sk);return -ESOCKTNOSUPPORT;free_and_badperm:sk_free(sk);return -EPERM;free_and_noproto:sk_free(sk);return -EPROTONOSUPPORT;do_oom:return -ENOBUFS;}; net/core/sock.c:#define sock_lock_init(__sk) \do { spin_lock_init(&((__sk)->lock.slock)); \(__sk)->ers = 0; \init_waitqueue_head(&((__sk)->lock.wq)); \} while(0);struct sock *sk_alloc(int family, int priority, int zero_it){struct sock *sk = kmem_cache_alloc(sk_cachep, priority); if(sk && zero_it) {memset(sk, 0, sizeof(struct sock));sk->family = family;sock_lock_init(sk);}return sk;}void sock_init_data(struct socket *sock, struct sock *sk) {skb_queue_head_init(&sk->receive_queue);skb_queue_head_init(&sk->write_queue);skb_queue_head_init(&sk->error_queue);init_timer(&sk->timer);sk->allocation = GFP_KERNEL;sk->rcvbuf = sysctl_rmem_default;sk->sndbuf = sysctl_wmem_default;sk->state = TCP_CLOSE;sk->zapped = 1;sk->socket = sock;if(sock){sk->type = sock->type;sk->sleep = &sock->wait;sock->sk = sk;} elsesk->sleep = NULL;sk->dst_lock = RW_LOCK_UNLOCKED;sk->callback_lock = RW_LOCK_UNLOCKED;sk->state_change = sock_def_wakeup;sk->data_ready = sock_def_readable;sk->write_space = sock_def_write_space;sk->error_report = sock_def_error_report;sk->destruct = sock_def_destruct;sk->peercred.pid = 0;sk->peercred.uid = -1;sk->peercred.gid = -1;sk->rcvlowat = 1;sk->rcvtimeo = MAX_SCHEDULE_TIMEOUT;sk->sndtimeo = MAX_SCHEDULE_TIMEOUT;atomic_set(&sk->refcnt, 1);}。
12-原始套接字
第13章原始套接字利用“原始套接字”(Raw Socket),我们可访问位于基层的传输协议。
本章专门讲解如何运用这种原始套接字,来模拟I P的一些实用工具,比如Tr a c e r o u t e和P i n g程序等等。
使用原始套接字,亦可对I P头信息进行实际的操作。
本章只关心I P协议;至于如何针对其他协议使用原始套接字,我们不打算提及。
而且,大多数协议(除AT M以外)根本就不支持原始套接字。
所有原始套接字都是使用S O C K_R A W这个套接字类型来创建的,而且目前只有Wi n s o c k 2提供了对它的支持。
因此,无论Microsoft Windows CE还是老版本的Windows 95(无Winsock 2升级)均不能利用原始套接字的能力。
此外,要想顺利使用原始套接字,要求对基层的协议结构有一定程度的认识,而那已超出了本书的范围。
在这一章中,我们打算讨论I n t e r n e t控制消息协议(I C M P)、I n t e r n e t组管理协议(I G M P)以及用户数据报协议(U D P)。
I C M P会由P i n g这个实用程序用到,以便探测到某个主机的路由是否有效和畅通,看看对方的机器是否会作出响应。
对程序开发者来说,经常都要用到一种程序化的方法,以便判断一台机器是否“活动”,网络数据能否抵达它。
I P多播通信利用I G M P将多播组成员信息通告给路由器。
大多数Wi n32平台目前都增加了对I G M P 第2版的支持。
但在某些情况下,我们也需要送出自己的I G M P数据包,以便脱离组成员关系。
至于U D P协议,我们打算把它同I P_H D R I N C L这个套接字选项组合起来讨论。
以它为例,讲述如何发送自己的I G M P包。
对这三种协议来说,我们都只会讲解与本章示范代码及示范程序密切相关的那些部分。
13.1 原始套接字的创建要想使用原始套接字,第一步便是创建它。
socket套接字及缓冲区详解(一篇搞定~)
socket套接字及缓冲区详解(一篇搞定~)文章目录一、域(domain)二、类型(type)三、协议(protocol)四、socket缓冲区以及阻塞模式1、缓冲区简介2、使用write()/send()发送数据3、使用read()/recv()读取数据4、系统调用read()的返回错误场景五、面试题--->TCP服务端一直sleep,客户端发送数据问题1、TCP发送数据的过程2、阻塞方式的情况3、非阻塞方式的情况套接字是一种通信机制(通信的两方的一种约定),凭借这种机制,不同主机之间的进程可以进行通信。
我们可以用套接字中的相关函数来完成通信过程。
套接字的特性有三个属性确定,它们是:域(domain),类型(type),和协议(protocol)。
#include<sys/types.h>#include<sys/socket.h>int socket(int domain, int type, int protocol);一、域(domain)域指定套接字通信中使用的网络介质。
最常见的套接字域是AF_INET(IPv4)或者AF_INET6(IPV6),它是指 Internet 网络,许多Linux 局域网使用的都是该网络,当然,因特网自身用的也是它。
二、类型(type)流套接字(SOCK_STREAM):流套接字用于提供面向连接、可靠的数据传输服务。
该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。
流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(The Transmission Control Protocol)协议。
数据报套接字(SOCK_DGRAM):数据报套接字提供了一种无连接的服务。
该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。
数据报套接字使用UDP(User Datagram Protocol)协议进行数据的传输。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
详细说明:原始套接字(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) 发送一个以零结尾的字符串。
6.#define PSOCK_GENERATOR_SEND(psock, generator, arg) 通过函数(generator)产生数据并发送出去。
7.#define PSOCK_CLOSE(psock) 关闭一个原始套接字。
8.#define PSOCK_READBUF(psock) 读数据直到缓冲区满。
9.#define PSOCK_READTO(psock, c) 读数据到字符c.10.#define PSOCK_DATALEN(psock) 获得上次读到的数据长度。
11.#define PSOCK_EXIT(psock) 退出原始套接字的原始线程。
12.#define PSOCK_CLOSE_EXIT(psock) 关闭一个原始套接字,并退出其原始线程。
13.#define PSOCK_END(psock) 声明一个原始套接字的原始线程的结尾。
14.#define PSOCK_NEWDATA(psock) 查明是否有数据到达原始套接字。
15.#define PSOCK_WAIT_UNTIL(psock, condition) 等待,直到条件(condition)为真。
16.#define PSOCK_WAIT_THREAD(psock,condition) PT_WAIT_THREAD(&((psock)->pt), (condition))复制代码相关函数:1.u16_t psock_datalen(struct psock *psock) char psock_newdata(psock * s)1. #define PSOCK_BEGIN(psock)启用一个原始套接字的原始线程。
此宏启用一个原始套接字关联的原始线程,必须在使用此原始套接字的函数调用其他原始套接字函数之前出现。
参数:psock (struct psock *)指向要启用的原始套接字的结构体指针。
应用例程:hello-world.c, and smtp.c.定义于psock.h的158行.2. #define PSOCK_CLOSE(psock)此宏用于关闭一个原始套接字,只能用于此原始套接字生存的原始线程中.参数:psock (struct psock *)指向要关闭的原始套接字的结构体指针。
应用例程:hello-world.c, and smtp.c.定义于psock.h的235行.3. #define PSOCK_CLOSE_EXIT(psock)此宏用于关闭一个原始套接字,并退出原始套接字生存的线程.参数:psock (struct psock *)指向要关闭的原始套接字的结构体指针。
定义于psock.h的308行.4. #define PSOCK_DATALEN(psock)返回之前通过PSOCK_READTO()或PSOCK_READ()读到的数据长度.参数:psock (struct psock *)指向盛放数据的原始套接字的结构体指针。
定义于psock.h的281行.5. #define PSOCK_END(psock)此宏用于声明原始套接字的原始线程结束.常于PSOCK_BEGIN(psock)配合使用.参数:psock (struct psock *)指向原始套接字的结构体指针应用例程:hello-world.c, and smtp.c.定义于psock.h的325行.6. #define PSOCK_EXIT(psock)此宏用于终止原始套接字的原始线程,必须与PSOCK_CLOSE一起使用.也可以直接使用PSOCK_CLOSE_EXIT();参数:psock (struct psock *)指向原始套接字的结构体指针.应用例程:smtp.c.定义于psock.h的297行.7. #define PSOCK_GENERATOR_SEND(psock,generator,arg)通过函数产生数据并发送.参数:psock 指向原始套接字的指针.generator 指向产生数据的函数的指针.arg 要传给函数的参数.使宏用于通过函数产生数据,并通过原始套接字发送.它可以用于动态产生数据并传输,而不必先将产生的数据存入缓冲区.此函数减小了缓冲区内存的开销.产生器函数由应用程序实现,使用时要将函数的指针作为一个参数传给宏.产生器函数应该将产生的数据直接存放在uip_appdata缓冲区中,并返回产生数据的长度.数据每一次发送时,原始套接字层会调用产生器函数,并且如果出现重发的情况,则也会调用一次产生器函数,也就是说重发的值并非第一次产生器函数调用时的值.定义于psock.h的219行.8. #define PSOCK_INIT(psock ,buffer,buffersize)这个宏初始化一个原始套接字,它必须在使用套接字之间得到调用. 此宏还规定了套接字的输入缓冲区.参数:psock (struct psock *) 指向要初始化的原始套接字的指针.buffer (char * ) 指向原始套接字的输入缓冲区的指针.buffersize (unsigned int) 输入缓冲区的大小.应用例程:hello-world.c, and smtp.c.定义于psock.h的144行.9. #define PSOCK_NEWDATA(psock)此宏用于查明是否有数据到达套接字。
它常和PSOCK_WAIT_UNTIL() 连用,查看套接字上是否有新的数据到达。
参数:psock (struct psock *) 指向套接字的指针。
定义于psock.h的339行。
10. #define PSOCK_READBUF(psock)读数据直到缓冲区满。
此宏会阻塞数据等待,把数据读入由PSOCK_INIT()指定的输入缓冲区。
读数据操作会进行到缓冲区满为止。
参数:psock (struct psock *) 指向数据读取来源套接字的指针。
定义于psock.h的250行。
11. #define PSOCK_READTO(psock,c)读数据直到某字符出现。
此宏会阻塞数据等待并开始读取数据到由PSOCK_INIT()指定的输入缓冲区,数据读取会一直持续到由参数c指定的字符出现为止。
参数:psock (struct psock *)指向数据读取来源套接字的指针。
c (char )用于指示停止读取数据的字符。
应用例程:hello-world.c, and smtp.c.定义于psock.h的268行。
12. #define PSOCK_SEND(psock,data,datalen)发送数据。
此宏通过原始套接字发送数据。
原始套接字阻塞原始线程,直到所有的数据发送完毕,并且已经被完程TCP终端接收。
参数:psock (struct psock *) 指向用于发送数据的原始套接字的指针。
data (char *) 指向要发送的数据的指针。
datalen (unsigned int)要发送的数据长度。
应用例程:smtp.c.定义于psock.h的178行。
13. #define PSOCK_SEND_STR(psock,str)发送一个以零结尾的字符串。
参数:psock (struct psock *) 指向要用来发送数据的套接字指针。
str 要发送的字符串。
应用例程:hello-world.c, and smtp.c.定义于psock.h的191行。
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. }复制代码参数:psock (struct psock *)套接字指针。
condition 等待条件。
定义于psock.h的372行。