socket编程(二)- 使用详解

[复制链接]
查看718 | 回复3 | 2023-9-5 11:10:00 | 显示全部楼层 |阅读模式

上一篇文章中简单介绍了socket,文章最后贴了一个小小的demo,从函数调用流程来看,其实就能明白socket使用的一个逻辑。那么这篇文章,就深入研究一下,每一个步骤里的每一个参数都是什么意思?

回顾demo

代码段:socket_demo.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int server_socket()
{
    int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  // 创建socket,返回值实际上就是一个fd

    struct sockaddr_in server_addr;  // 配置服务端IP和端口
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.10");
    server_addr.sin_port = htons(6666);
    bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));  // 将socket和IP以及端口绑定
    listen(server_socket, 20);  // 开始监听
    struct sockaddr_in client_addr;
    socklen_t client_addr_size = sizeof(client_addr);
    while (1) {
        // accept函数会阻塞等待客户端的连接,并返回客户端的socket
        int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_size);
        char str[] = "Hello Socket!";
        send(client_socket, str, sizeof(str), 0);  // 发送Hello Socket给客户端  
        close(client_socket);
    }
    close(server_socket);
    return 0;
}


int client_socket()
{
    int client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.10");
    server_addr.sin_port = htons(6666);
    connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));

    char buffer[15];
    recv(client_socket, buffer, 15, 0);
    printf("Message form server: %s\n", buffer);

    close(client_socket);
    return 0;
}

代码段:common.h

#ifndef _COMMON_H
#define _COMMON_H

extern int server_socket();
extern int client_socket();

#endif  /* _COMMON_H */

细说demo

我不不妨把server和client中的函数调用,做成一个流程去看:

server:

  1. socket()
  2. bind()
  3. listen()
  4. accept()
  5. send()
  6. close()

client:

  1. socket()
  2. connect()
  3. recv()
  4. close()

然后我门再在函数调用流程上开支散叶,细说每一个函数,socket.h 中有每一个函数的原型以及简单的说明,相关的文件我放在文件的末尾:附录1

socket()函数

socket函数的原型是:int socket(int af, int type, int protocol);

返回值:int类型,实际上,socket返回的是一个文件描述符,可以直接使用read和write函数操作这个文件描述符。它通常是一个比较小的数值。这里多一嘴,如果你从log中发现,某次申请到的文件描述符比较大,大是什么概念?大于100都算大!你就应该查看代码是不是又申请文件描述符未close。

参数:

  • int af

    af是Address Family的缩写,翻译为地址族,也就是IP地址类型。在socket.h头文件中,地址族定义了很多,但是目前我们常使用的依然是IPv4的地址类型,即AF_INET,可能会有情况也会遇到使用IPv6类型的地址,即AF_INET6.但是这种情况,比较少见,所以此处不多做讨论。

  • int type

    type就表示使用的socket类型,在第一篇socket系列文章中就已说明,我们常用的socket类型又流式套接字和数据报式套接字。参数分别为:

    • 流式套接字(SOCK_STREAM)
    • 数据报式套接字 (SOCK_DGRAM)
  • int protocol

    protocol表示协议,常用的协议就是TCP和UDP,参数分别为:

    • TCP: IPPROTO_TCP
    • UDP: IPPROTO_UDP

    所以socket常用的调用语句是:

    int server_socket = socket(AF_INET, SOCK_STREAK, IPPROTO_TCP);

bind()函数

bind()函数的原型是:int bind(int sock, struct sockaddr * addr, socklen_t addrlen);

返回值:int 类型,表示错误码,正常绑定返回0,否则返回-1,并设置error变量。常见的错误类型包括:

  • EADDRINUSE:指定的端口已经被其他进程占用。
  • EMSGSIZE:提供给套接字的数据报太大。
  • ENOBUFS:系统缓冲区不足。
  • EPROTONOSUPPORT:不支持指定的协议族。
  • EINVAL:提供的参数无效。

参数:

  • int sock : 也就是上面通过socket函数生成的socket文件描述符
  • struct sockaddr * addr : socket地址
  • socklen_t addrlen : socket地址长度
sockaddr结构

上面的addrlen和sock两个参数都没什么好说的,只有addr,可以看到在上面demo中填充addr结构的方式有些特殊,做法是先生成sockaddr_in结构体变量,然后填充该结构体,最后强转成sockaddr结构体。我们不妨来看看这两个结构体:

sockaddr_in结构体:

struct sockaddr_in{
    sa_family_t     sin_family;   //地址族(Address Family),也就是地址类型
    uint16_t        sin_port;     //16位的端口号
    struct in_addr  sin_addr;     //32位IP地址
    char            sin_zero[8];  //不使用,一般用0填充
};

sockaddr结构体:

struct sockaddr{
    sa_family_t  sin_family;   //地址族(Address Family),也就是地址类型
    char         sa_data[14];  //IP地址和端口号
};

可以对比以上两个结构体,发现地址族这个字节是公共的,大家都有。不同的是IP和端口的表述上,对于sockaddr_in结构体,他是将端口和IP分开,这样在赋值的时候可以分开赋值。但是对于sockaddr结构体,如果要写IP和端口,就得对"192.168.1.10:6666"字符串进行特殊处理。

所以为什么会存在sockaddr这样的结构体,而不是直接使用sockaddr_in来代替它?因为sockaddr实际上是兼容了所有的地址族,而后者是对IPv4的实现。这样子是不是就能理解了。

因此bind()函数和sockaddr结构填充最典型的实现代码如下:

    struct sockaddr_in server_addr;
    memset(server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;  // 这里需要注意和socket函数中使用的地址族统一
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.10");
    server_addr.sin_port = htons(6666);
    bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));

listen()函数

listen()函数的原型:int listen(int sock, int backlog);

返回值: int 类型的错误码,正常执行返回0 ,执行异常返回-1,并设置error变量。

参数:

  • int sock : 服务端的socket文件描述符,进入被动监听状态,当没有客户端连接的时候该socket处于睡眠状态,又客户端连接则唤醒。
  • int backlog : 表示最大缓冲队列,socket服务端同时只处理一个socket客户端的事务,此时其他socket等待连接,listen监听到这些客户端之后会将他们放入缓冲区。此参数就表示可以放入缓冲区的socket队列大小。

提醒:listen()只是让服务端socket开始监听,并不能进行连接,相当于是我的店铺早上开门了,但是暂时还不能开始卖包子,因为包子还没熟!!

所以,listen()函数的常用实现是:

    listen(server_socket, 20);

accept()函数

调用到accept()函数的时候包子就输了,现在可以开始卖了!

accept()函数原型:int accept(int sock, struct sockaddr * addr, socklen_t * addrlen);

返回值: int 类型的socket文件描述符。这里出现了server端的第二个套接字。为什么要生成一个新的套接字来和客户端通信而不是使用服务端的套接字呢?因为socket通信并不是一对一的通信,有可能多个客户端都需要通过想用的ip和端口对服务端进行访问,因此每次访问都使用新的套接字进行通信,避免了数据的污染。

参数:

  • int sock : 服务端的socket,表示是该服务端正在接收连接
  • struct sockaddr * addr : 客户端的sockaddr,表示该客户端的地址信息
  • socklen_t * addrlen : 客户端地址长度

上面的sockaddr需要特别注意是客户端的地址信息,accept需要传入这个参数来报错连接过来的客户端的地址信息,方便接下来的通信。

综上,accept()函数常用实现方式:

    struct sockaddr_in client_addr;
    memset(client_addr, 0, sizeof(client_addr));
    socklen_t client_addr_len;
    while (1) {
        int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_size);
        ...
        close(client_socket);
    }

connect()函数

上面服务端执行完accept()函数之后,程序就进入阻塞状态了,指导客户端调用connect()函数连接服务端。connect()函数的原型:int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);

返回值: 与bind函数类似,返回值表示错误码,成功0,失败-1

参数:

  • int sock : 客户端初始化的时候也会新建一个client_socket文件描述符,在这里,client_socket解决了连接从哪里来的问题,能够告诉服务端是谁要和你进行连接
  • struct sockaddr * server_addr : 服务端的地址信息
  • socklen_t addr_len : 服务端地址信息长度

所以connect()也就是客户端的典型实现如下:

    int client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.10");
    server_addr.sin_port = htons(6666);
    connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));

到这里,客户端与服务端就已经建立了连接,那么建立连接之后可以做点啥呢?我们指导socket是一个通信工具,最重要的目的就是完成两个设备之间的通信问题。所以接下来来看看socket的通信接口。

socket通信接口

如果看这篇文章的你熟悉linux系统编程,相信你对read()write() 函数就再了解不过了。他们的原型分别是:

  • write:ssize_t write(int fd, const void *buf, size_t nbytes);
  • read:ssize_t read(int fd, void *buf, size_t nbytes);

具体的参数就不赘述了,因为原型里面写的很明显了。他们的返回值都表示长度,写入函数返回写入的长度,读取函数返回读到的长度。他们常常和open()函数、close()函数配合使用。这就涉及到Linux系统编程了,不赘述。

而socket通信接口就是对write和read函数的封装而已。

来看send和recv的原型:

  • send: ssize_t send(int fd, const void * buff, size_t nbytes, int flags);
  • recv: ssize_t recv(int fd, void * buff, size_t nbytes, int flags);

很容易看到相比于read和write,只多出一个flags参数。它是一个标志位,用于指定发送操作的行为。具体来说,这个标志位可以是以下值之一:

  • 0:非阻塞模式,如果发送缓冲区已满,则立即返回EAGAIN或EWOULDBLOCK错误;否则,返回0。
  • 1:同步阻塞模式,如果发送缓冲区已满,则等待直到有空间可用或接收方关闭连接;否则,返回0。
  • 2:异步非阻塞模式,如果发送缓冲区已满,则立即返回EAGAIN或EWOULDBLOCK错误;否则,返回发送的字节数。

实际上我们使用过程中如果没有特殊需求,一般都是用非阻塞模式进行传输。

所以收发常用的实现方式:

    send(client_socket, str, sizeof(str), 0);
    recv(client_socket, buffer, sizeof(buffer), 0);

小结

上面的demo说到这里,实际上就已经结束了。记性好的小伙伴可能会发现close()函数还没说,但是有必要说吗?很有必要!是的,所以我要在小结中说说close()函数。

close()函数很简单,就传入一个文件描述符,把这个文件描述符释放就可以了。就这样!然而再Linux系统编程中,忘记释放文件描述符确实常有的事情,而且引起的后果往往就是程序崩溃。

分享我最近写的两个bug,都是文件描述符忘记释放。

bug 1

Linux系统编程中需要使用串口/dev/ttySx 收发数据,收发我写了一个公共的函数sendMessage()recvMessage ,bug就在于receive函数中忘记写close()函数了。我自测的时候由于是少量单次读取串口,所以并没有发现问题,可是当app的小伙伴把app跑起来之后,1分钟必崩,他就是需要持续读串口,500ms一次。最后从Log中发现,最后一次申请到文件描述符已经三千多了。经过排查发现了这个问题。

bug 2

Linux系统编程,调用read函数,由于没有阻塞机制,所以使用epoll进行阻塞读取,使用epoll需要进行创建,“Linux一切皆文件”,所以调用epoll_create()函数会生成epoll的文件描述符,是的,我又忘记释放了。app运行到十分钟左右又会崩溃。

所以,不释放文件描述符,后果真的是惨重的。

附录

附录1 socket.h

#ifndef _SYS_SOCKET_H_
#define _SYS_SOCKET_H_

/* get the definitions for struct iovec, size_t, ssize_t, and <sys/cdefs.h> */
#include <sys/uio.h>

#if __BSD_VISIBLE
#include <sys/types.h>          /* for off_t, uid_t, and gid_t */
#endif

#ifndef _SOCKLEN_T_DEFINED_
#define _SOCKLEN_T_DEFINED_
typedef __socklen_t socklen_t;  /* length type for network syscalls */
#endif

#ifndef _SA_FAMILY_T_DEFINED_
#define _SA_FAMILY_T_DEFINED_
typedef __sa_family_t   sa_family_t;    /* sockaddr address family type */
#endif


/*
 * Definitions related to sockets: types, address families, options.
 */

/*
 * Types
 */
#define SOCK_STREAM 1       /* stream socket */
#define SOCK_DGRAM  2       /* datagram socket */
#define SOCK_RAW    3       /* raw-protocol interface */
#define SOCK_RDM    4       /* reliably-delivered message */
#define SOCK_SEQPACKET  5       /* sequenced packet stream */
#ifdef _KERNEL
#define SOCK_TYPE_MASK  0x000F      /* mask that covers the above */
#endif

/*
 * Socket creation flags
 */
#if __BSD_VISIBLE
#define SOCK_CLOEXEC        0x8000  /* set FD_CLOEXEC */
#define SOCK_NONBLOCK       0x4000  /* set O_NONBLOCK */
#ifdef _KERNEL
#define SOCK_NONBLOCK_INHERIT   0x2000  /* inherit O_NONBLOCK from listener */
#endif
#define SOCK_DNS        0x1000  /* set SS_DNS */
#endif /* __BSD_VISIBLE */

/*
 * Option flags per-socket.
 */
#define SO_DEBUG    0x0001      /* turn on debugging info recording */
#define SO_ACCEPTCONN   0x0002      /* socket has had listen() */
#define SO_REUSEADDR    0x0004      /* allow local address reuse */
#define SO_KEEPALIVE    0x0008      /* keep connections alive */
#define SO_DONTROUTE    0x0010      /* just use interface addresses */
#define SO_BROADCAST    0x0020      /* permit sending of broadcast msgs */
#define SO_USELOOPBACK  0x0040      /* bypass hardware when possible */
#define SO_LINGER   0x0080      /* linger on close if data present */
#define SO_OOBINLINE    0x0100      /* leave received OOB data in line */
#define SO_REUSEPORT    0x0200      /* allow local address & port reuse */
#define SO_TIMESTAMP    0x0800      /* timestamp received dgram traffic */
#define SO_BINDANY  0x1000      /* allow bind to any address */
#define SO_ZEROIZE  0x2000      /* zero out all mbufs sent over socket */

/*
 * Additional options, not kept in so_options.
 */
#define SO_SNDBUF   0x1001      /* send buffer size */
#define SO_RCVBUF   0x1002      /* receive buffer size */
#define SO_SNDLOWAT 0x1003      /* send low-water mark */
#define SO_RCVLOWAT 0x1004      /* receive low-water mark */
#define SO_SNDTIMEO 0x1005      /* send timeout */
#define SO_RCVTIMEO 0x1006      /* receive timeout */
#define SO_ERROR    0x1007      /* get error status and clear */
#define SO_TYPE     0x1008      /* get socket type */
#define SO_NETPROC  0x1020      /* multiplex; network processing */
#define SO_RTABLE   0x1021      /* routing table to be used */
#define SO_PEERCRED 0x1022      /* get connect-time credentials */
#define SO_SPLICE   0x1023      /* splice data to other socket */
#define SO_DOMAIN   0x1024      /* get socket domain */
#define SO_PROTOCOL 0x1025      /* get socket protocol */

/*
 * Structure used for manipulating linger option.
 */
struct  linger {
    int l_onoff;        /* option on/off */
    int l_linger;       /* linger time */
};

#if __BSD_VISIBLE

#ifndef _TIMEVAL_DECLARED
#define _TIMEVAL_DECLARED
struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* and microseconds */
};
#endif

/*
 * Structure used for manipulating splice option.
 */
struct  splice {
    int sp_fd;          /* drain socket file descriptor */
    off_t   sp_max;         /* if set, maximum bytes to splice */
    struct  timeval sp_idle;    /* idle timeout */
};

/*
 * Maximum number of alternate routing tables
 */
#define RT_TABLEID_MAX      255
#define RT_TABLEID_BITS     8
#define RT_TABLEID_MASK     0xff

#endif /* __BSD_VISIBLE */

/*
 * Level number for (get/set)sockopt() to apply to socket itself.
 */
#define SOL_SOCKET  0xffff      /* options for socket level */

/*
 * Address families.
 */
#define AF_UNSPEC   0       /* unspecified */
#define AF_UNIX     1       /* local to host */
#define AF_LOCAL    AF_UNIX     /* draft POSIX compatibility */
#define AF_INET     2       /* internetwork: UDP, TCP, etc. */
#define AF_IMPLINK  3       /* arpanet imp addresses */
#define AF_PUP      4       /* pup protocols: e.g. BSP */
#define AF_CHAOS    5       /* mit CHAOS protocols */
#define AF_NS       6       /* XEROX NS protocols */
#define AF_ISO      7       /* ISO protocols */
#define AF_OSI      AF_ISO
#define AF_ECMA     8       /* european computer manufacturers */
#define AF_DATAKIT  9       /* datakit protocols */
#define AF_CCITT    10      /* CCITT protocols, X.25 etc */
#define AF_SNA      11      /* IBM SNA */
#define AF_DECnet   12      /* DECnet */
#define AF_DLI      13      /* DEC Direct data link interface */
#define AF_LAT      14      /* LAT */
#define AF_HYLINK   15      /* NSC Hyperchannel */
#define AF_APPLETALK    16      /* Apple Talk */
#define AF_ROUTE    17      /* Internal Routing Protocol */
#define AF_LINK     18      /* Link layer interface */
#define pseudo_AF_XTP   19      /* eXpress Transfer Protocol (no AF) */
#define AF_COIP     20      /* connection-oriented IP, aka ST II */
#define AF_CNT      21      /* Computer Network Technology */
#define pseudo_AF_RTIP  22      /* Help Identify RTIP packets */
#define AF_IPX      23      /* Novell Internet Protocol */
#define AF_INET6    24      /* IPv6 */
#define pseudo_AF_PIP   25      /* Help Identify PIP packets */
#define AF_ISDN     26      /* Integrated Services Digital Network*/
#define AF_E164     AF_ISDN     /* CCITT E.164 recommendation */
#define AF_NATM     27      /* native ATM access */
#define AF_ENCAP    28
#define AF_SIP      29      /* Simple Internet Protocol */
#define AF_KEY      30
#define pseudo_AF_HDRCMPLT 31       /* Used by BPF to not rewrite headers
                       in interface output routine */
#define AF_BLUETOOTH    32      /* Bluetooth */
#define AF_MPLS         33              /* MPLS */
#define pseudo_AF_PFLOW 34      /* pflow */
#define pseudo_AF_PIPEX 35      /* PIPEX */
#define AF_MAX          36

/*
 * Structure used by kernel to store most
 * addresses.
 */
struct sockaddr {
    __uint8_t    sa_len;        /* total length */
    sa_family_t sa_family;      /* address family */
    char        sa_data[14];    /* actually longer; address value */
};

/*
 * Sockaddr type which can hold any sockaddr type available
 * in the system.
 *
 * Note: __ss_{len,family} is defined in RFC2553.  During RFC2553 discussion
 * the field name went back and forth between ss_len and __ss_len,
 * and RFC2553 specifies it to be __ss_len.  openbsd picked ss_len.
 * For maximum portability, userland programmer would need to
 * (1) make the code never touch ss_len portion (cast it into sockaddr and
 * touch sa_len), or (2) add "-Dss_len=__ss_len" into CFLAGS to unify all
 * occurrences (including header file) to __ss_len.
 */
struct sockaddr_storage {
    __uint8_t   ss_len;     /* total length */
    sa_family_t ss_family;  /* address family */
    unsigned char   __ss_pad1[6];   /* align to quad */
    __uint64_t  __ss_pad2;  /* force alignment for stupid compilers */
    unsigned char   __ss_pad3[240]; /* pad to a total of 256 bytes */
};

#ifdef _KERNEL
/*
 * Structure used by kernel to pass protocol
 * information in raw sockets.
 */
struct sockproto {
    unsigned short  sp_family;  /* address family */
    unsigned short  sp_protocol;    /* protocol */
};
#endif /* _KERNEL */

/*
 * Protocol families, same as address families for now.
 */
#define PF_UNSPEC   AF_UNSPEC
#define PF_LOCAL    AF_LOCAL
#define PF_UNIX     AF_UNIX
#define PF_INET     AF_INET
#define PF_IMPLINK  AF_IMPLINK
#define PF_PUP      AF_PUP
#define PF_CHAOS    AF_CHAOS
#define PF_NS       AF_NS
#define PF_ISO      AF_ISO
#define PF_OSI      AF_ISO
#define PF_ECMA     AF_ECMA
#define PF_DATAKIT  AF_DATAKIT
#define PF_CCITT    AF_CCITT
#define PF_SNA      AF_SNA
#define PF_DECnet   AF_DECnet
#define PF_DLI      AF_DLI
#define PF_LAT      AF_LAT
#define PF_HYLINK   AF_HYLINK
#define PF_APPLETALK    AF_APPLETALK
#define PF_ROUTE    AF_ROUTE
#define PF_LINK     AF_LINK
#define PF_XTP      pseudo_AF_XTP   /* really just proto family, no AF */
#define PF_COIP     AF_COIP
#define PF_CNT      AF_CNT
#define PF_IPX      AF_IPX      /* same format as AF_NS */
#define PF_INET6    AF_INET6
#define PF_RTIP     pseudo_AF_RTIP  /* same format as AF_INET */
#define PF_PIP      pseudo_AF_PIP
#define PF_ISDN     AF_ISDN
#define PF_NATM     AF_NATM
#define PF_ENCAP    AF_ENCAP
#define PF_SIP      AF_SIP
#define PF_KEY      AF_KEY
#define PF_BPF      pseudo_AF_HDRCMPLT
#define PF_BLUETOOTH    AF_BLUETOOTH
#define PF_MPLS     AF_MPLS
#define PF_PFLOW    pseudo_AF_PFLOW
#define PF_PIPEX    pseudo_AF_PIPEX
#define PF_MAX      AF_MAX

/*
 * These are the valid values for the "how" field used by shutdown(2).
 */
#define SHUT_RD     0
#define SHUT_WR     1
#define SHUT_RDWR   2

#if __BSD_VISIBLE
#define SA_LEN(x) ((x)->sa_len)

/* Read using getsockopt() with SOL_SOCKET, SO_PEERCRED */
struct sockpeercred {
    uid_t       uid;        /* effective user id */
    gid_t       gid;        /* effective group id */
    pid_t       pid;
};

/*
 * Definitions for network related sysctl, CTL_NET.
 *
 * Second level is protocol family.
 * Third level is protocol number.
 *
 * Further levels are defined by the individual families below.
 */
#define NET_MAXID   AF_MAX

#define CTL_NET_NAMES { \
    { 0, 0 }, \
    { "unix", CTLTYPE_NODE }, \
    { "inet", CTLTYPE_NODE }, \
    { "implink", CTLTYPE_NODE }, \
    { "pup", CTLTYPE_NODE }, \
    { "chaos", CTLTYPE_NODE }, \
    { "xerox_ns", CTLTYPE_NODE }, \
    { "iso", CTLTYPE_NODE }, \
    { "ecma", CTLTYPE_NODE }, \
    { "datakit", CTLTYPE_NODE }, \
    { "ccitt", CTLTYPE_NODE }, \
    { "ibm_sna", CTLTYPE_NODE }, \
    { "decnet", CTLTYPE_NODE }, \
    { "dec_dli", CTLTYPE_NODE }, \
    { "lat", CTLTYPE_NODE }, \
    { "hylink", CTLTYPE_NODE }, \
    { "appletalk", CTLTYPE_NODE }, \
    { "route", CTLTYPE_NODE }, \
    { "link", CTLTYPE_NODE }, \
    { "xtp", CTLTYPE_NODE }, \
    { "coip", CTLTYPE_NODE }, \
    { "cnt", CTLTYPE_NODE }, \
    { "rtip", CTLTYPE_NODE }, \
    { "ipx", CTLTYPE_NODE }, \
    { "inet6", CTLTYPE_NODE }, \
    { "pip", CTLTYPE_NODE }, \
    { "isdn", CTLTYPE_NODE }, \
    { "natm", CTLTYPE_NODE }, \
    { "encap", CTLTYPE_NODE }, \
    { "sip", CTLTYPE_NODE }, \
    { "key", CTLTYPE_NODE }, \
    { "bpf", CTLTYPE_NODE }, \
    { "bluetooth", CTLTYPE_NODE }, \
    { "mpls", CTLTYPE_NODE }, \
    { "pflow", CTLTYPE_NODE }, \
    { "pipex", CTLTYPE_NODE }, \
}

/*
 * PF_ROUTE - Routing table
 *
 * Four additional levels are defined:
 *  Fourth: address family, 0 is wildcard
 *  Fifth: type of info, defined below
 *  Sixth: flag(s) to mask with for NET_RT_FLAGS
 *  Seventh: routing table to use (facultative, defaults to 0)
 *       NET_RT_TABLE has the table id as sixth element.
 */
#define NET_RT_DUMP 1       /* dump; may limit to a.f. */
#define NET_RT_FLAGS    2       /* by flags, e.g. RESOLVING */
#define NET_RT_IFLIST   3       /* survey interface list */
#define NET_RT_STATS    4       /* routing table statistics */
#define NET_RT_TABLE    5
#define NET_RT_IFNAMES  6
#define NET_RT_SOURCE   7
#define NET_RT_MAXID    8

#define CTL_NET_RT_NAMES { \
    { 0, 0 }, \
    { "dump", CTLTYPE_STRUCT }, \
    { "flags", CTLTYPE_STRUCT }, \
    { "iflist", CTLTYPE_STRUCT }, \
    { "stats", CTLTYPE_STRUCT }, \
    { "table", CTLTYPE_STRUCT }, \
    { "ifnames", CTLTYPE_STRUCT }, \
    { "source", CTLTYPE_STRUCT }, \
}

/*
 * PF_UNIX - unix socket tunables
 */
#define NET_UNIX_INFLIGHT   6
#define NET_UNIX_DEFERRED   7
#define NET_UNIX_MAXID      8

#define CTL_NET_UNIX_NAMES { \
    { 0, 0 }, \
    { "stream", CTLTYPE_NODE }, \
    { "dgram", CTLTYPE_NODE }, \
    { 0, 0 }, \
    { 0, 0 }, \
    { "seqpacket", CTLTYPE_NODE }, \
    { "inflight", CTLTYPE_INT }, \
    { "deferred", CTLTYPE_INT }, \
}

#define UNPCTL_RECVSPACE    1
#define UNPCTL_SENDSPACE    2
#define NET_UNIX_PROTO_MAXID    3

#define CTL_NET_UNIX_PROTO_NAMES { \
    { 0, 0 }, \
    { "recvspace", CTLTYPE_INT }, \
    { "sendspace", CTLTYPE_INT }, \
}

/*
 * PF_LINK - link layer or device tunables
 */
#define NET_LINK_IFRXQ      1   /* net.link.ifrxq */
#define NET_LINK_MAXID      2

#define CTL_NET_LINK_NAMES { \
    { 0, 0 }, \
    { "ifrxq", CTLTYPE_NODE }, \
}

#define NET_LINK_IFRXQ_PRESSURE_RETURN \
                1   /* net.link.ifrxq.pressure_return */
#define NET_LINK_IFRXQ_PRESSURE_DROP \
                2   /* net.link.ifrxq.pressure_drop */
#define NET_LINK_IFRXQ_MAXID    3

#define CTL_NET_LINK_IFRXQ_NAMES { \
    { 0, 0 }, \
    { "pressure_return", CTLTYPE_INT }, \
    { "pressure_drop", CTLTYPE_INT }, \
}

/*
 * PF_KEY - Key Management
 */
#define NET_KEY_SADB_DUMP   1   /* return SADB */
#define NET_KEY_SPD_DUMP    2   /* return SPD */
#define NET_KEY_MAXID       3

#define CTL_NET_KEY_NAMES { \
    { 0, 0 }, \
    { "sadb_dump", CTLTYPE_STRUCT }, \
    { "spd_dump", CTLTYPE_STRUCT }, \
}

/*
 * PF_BPF  not really a family, but connected under CTL_NET
 */
#define NET_BPF_BUFSIZE     1       /* default buffer size */
#define NET_BPF_MAXBUFSIZE  2       /* maximum buffer size */
#define NET_BPF_MAXID       3

#define CTL_NET_BPF_NAMES { \
    { 0, 0 }, \
    { "bufsize", CTLTYPE_INT }, \
    { "maxbufsize", CTLTYPE_INT }, \
}

/*
 * PF_PFLOW not really a family, but connected under CTL_NET
 */
#define NET_PFLOW_STATS     1       /* statistics */
#define NET_PFLOW_MAXID     2

#define CTL_NET_PFLOW_NAMES { \
    { 0, 0 }, \
    { "stats", CTLTYPE_STRUCT }, \
}
#endif /* __BSD_VISIBLE */

/*
 * Maximum queue length specifiable by listen(2).
 */
#define SOMAXCONN   128

/*
 * Message header for recvmsg and sendmsg calls.
 * Used value-result for recvmsg, value only for sendmsg.
 */
struct msghdr {
    void        *msg_name;  /* optional address */
    socklen_t   msg_namelen;    /* size of address */
    struct      iovec *msg_iov; /* scatter/gather array */
    unsigned int    msg_iovlen; /* # elements in msg_iov */
    void        *msg_control;   /* ancillary data, see below */
    socklen_t   msg_controllen; /* ancillary data buffer len */
    int     msg_flags;  /* flags on received message */
};

struct mmsghdr {
    struct msghdr msg_hdr;
    unsigned int msg_len;
};

struct timespec;

#define MSG_OOB         0x1 /* process out-of-band data */
#define MSG_PEEK        0x2 /* peek at incoming message */
#define MSG_DONTROUTE       0x4 /* send without using routing tables */
#define MSG_EOR         0x8 /* data completes record */
#define MSG_TRUNC       0x10    /* data discarded before delivery */
#define MSG_CTRUNC      0x20    /* control data lost before delivery */
#define MSG_WAITALL     0x40    /* wait for full request or error */
#define MSG_DONTWAIT        0x80    /* this message should be nonblocking */
#define MSG_BCAST       0x100   /* this message rec'd as broadcast */
#define MSG_MCAST       0x200   /* this message rec'd as multicast */
#define MSG_NOSIGNAL        0x400   /* do not send SIGPIPE */
#define MSG_CMSG_CLOEXEC    0x800   /* set FD_CLOEXEC on received fds */
#define MSG_WAITFORONE      0x1000  /* nonblocking but wait for one msg */

/*
 * Header for ancillary data objects in msg_control buffer.
 * Used for additional information with/about a datagram
 * not expressible by flags.  The format is a sequence
 * of message elements headed by cmsghdr structures.
 */
struct cmsghdr {
    socklen_t   cmsg_len;   /* data byte count, including hdr */
    int     cmsg_level; /* originating protocol */
    int     cmsg_type;  /* protocol-specific type */
/* followed by  u_char  cmsg_data[]; */
};

/* given pointer to struct cmsghdr, return pointer to data */
#define CMSG_DATA(cmsg) \
    ((unsigned char *)(cmsg) + _ALIGN(sizeof(struct cmsghdr)))

/* given pointer to struct cmsghdr, return pointer to next cmsghdr */
#define CMSG_NXTHDR(mhdr, cmsg) \
    (((char *)(cmsg) + _ALIGN((cmsg)->cmsg_len) + \
                _ALIGN(sizeof(struct cmsghdr)) > \
        ((char *)(mhdr)->msg_control) + (mhdr)->msg_controllen) ? \
        (struct cmsghdr *)NULL : \
        (struct cmsghdr *)((char *)(cmsg) + _ALIGN((cmsg)->cmsg_len)))

/*
 * RFC 2292 requires to check msg_controllen, in case that the kernel returns
 * an empty list for some reasons.
 */
#define CMSG_FIRSTHDR(mhdr) \
    ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
     (struct cmsghdr *)(mhdr)->msg_control : \
     (struct cmsghdr *)NULL)

/* Round len up to next alignment boundary */
#ifdef _KERNEL
#define CMSG_ALIGN(n)       _ALIGN(n)
#endif

/* Length of the contents of a control message of length len */
#define CMSG_LEN(len)   (_ALIGN(sizeof(struct cmsghdr)) + (len))

/* Length of the space taken up by a padded control message of length len */
#define CMSG_SPACE(len) (_ALIGN(sizeof(struct cmsghdr)) + _ALIGN(len))

/* "Socket"-level control message types: */
#define SCM_RIGHTS  0x01        /* access rights (array of int) */
#define SCM_TIMESTAMP   0x04        /* timestamp (struct timeval) */

#ifndef _KERNEL

__BEGIN_DECLS
int accept(int, struct sockaddr *, socklen_t *);
int bind(int, const struct sockaddr *, socklen_t);
int connect(int, const struct sockaddr *, socklen_t);
int getpeername(int, struct sockaddr *, socklen_t *);
int getsockname(int, struct sockaddr *, socklen_t *);
int getsockopt(int, int, int, void *, socklen_t *);
int listen(int, int);
ssize_t recv(int, void *, size_t, int);
ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
ssize_t recvmsg(int, struct msghdr *, int);
int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *);
ssize_t send(int, const void *, size_t, int);
ssize_t sendto(int, const void *,
        size_t, int, const struct sockaddr *, socklen_t);
ssize_t sendmsg(int, const struct msghdr *, int);
int sendmmsg(int, struct mmsghdr *, unsigned int, int);
int setsockopt(int, int, int, const void *, socklen_t);
int shutdown(int, int);
int sockatmark(int);
int socket(int, int, int);
int socketpair(int, int, int, int *);

#if __BSD_VISIBLE
int accept4(int, struct sockaddr *__restrict, socklen_t *__restrict, int);
#endif

#if __BSD_VISIBLE
int getpeereid(int, uid_t *, gid_t *);
int getrtable(void);
int setrtable(int);
#endif /* __BSD_VISIBLE */

__END_DECLS

#else

static inline struct sockaddr *
sstosa(struct sockaddr_storage *ss)
{
    return ((struct sockaddr *)(ss));
}

#endif /* !_KERNEL */

#endif /* !_SYS_SOCKET_H_ */
回复

使用道具 举报

爱笑 | 2023-9-5 11:14:45 | 显示全部楼层
园长很满意!
用心做好保姆工作
回复 支持 反对

使用道具 举报

ai_mcu | 2023-9-5 13:44:39 | 显示全部楼层
你这文章质量,牛啊
明天总会更好
回复 支持 反对

使用道具 举报

jkernet | 2023-9-5 18:54:13 来自手机 | 显示全部楼层
干货满满
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则