linux C语言函数API--网络编程函数

五:网络编程函数

1.socket()创建网络插口函数


【原型】    int socket(int domain,int type,int protocol);
【头文件】 #include<sys/types.h>
            #include<sys/socket.h>
【功能】    创建网络插口
【参数】    domain : 设置网络通信的域,选择通信协议的族。
                    PF_UNIX,PF_LOCAL 本地通信
                    PF_INET     :IPv4 Internet 协议
                    PF_INET6    :IPv6 internet 协议
                    PF_IPX      : IPX-Novell 协议
                    PF_NETLINK  :内核用户界面设备
                    PF_X25      : ITU-T X.25/ISO-8208协议
                    PF_AX25     : Amateur radio AX.25 协议
                    PF_ATMPVC   : 原始ATMPVC 访问
                    PF_APPLETALK: Appletalk
                    PF_PACKET   : 底层包访问

            type : 用于设置套接字通信的类型
                    SOCK_STREAM : TCP连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
                    SOCK_DGRAM  : 支持UDP连接(无连接状态的消息)
                    SOCK_SEQPACKET : 序列化包,提供序列化的,可靠的,双向连接的字节流。支持带外数据传输。
                    SOCK_RAW    : RAW 类型,提供原始网络协议访问
                    SOCK_RDM    :提供可靠的数据报文,不过可能数据会有乱序
                    SOCK_PACKET : 这是一个专用类型,不能在通用程序中使用。
                    注意:并不是所有的协议簇都实现了这些协议类型。例如:AF_INET协议簇就没有实现
                            SOCK_SEQPACKET协议类型。
            protocol : 用于指定某个协议的特定类型,即type类型中的某个类型。通常设置为0
            
【返回值】 成功:返回文件描述符
            失败:返回错误码errno
            
                errno的参数如下:
                
                EACCES  :没有权限建立指定的domain的type的socket
                EAFNOSUPPORT :不支持所给的地址类型
                EINVAL : 不支持此协议或者协议不可用。
                EMFILE :已经达到系统允许打开的文件数量,打开文件过多。
                ENOBUFS/ENOMEM : 内存不足,socket 只有到资源足够或者有进程释放内存
                EPROTONOSUPPORT : 指定的协议type在domain中不存在

【注意点】
            1. 有些协议有多种特定的类型,就需要设置protocol这个参数来选择特定的类型。
            2. 类型为SOCK_STREAM的套接字表示一个双向的字节流,与管道类似。
            3. 流式的套接字在进行数据收发之前必须已经连接。连接使用connect()函数进行
            4.  流式的通信方式保证数据不会丢失或者重复接收,
                当数据在一段时间内仍然没有接收完毕,可以将这个连接认为已经死掉。
            5. SOCK_PACKET是一种专用的数据包,它直接从设备驱动接收数据。
            6.  socket()并不总是执行成功,失败原因可以通过errno获得。
        
        



2. bind()绑定一个地址端口

    【原型】    int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);
    【头文件】 #include <sys/types.h>
                #include <sys/socket.h>
    【功能】    绑定一个地址端口
    【参数】    sockfd : socket创建的socket描述符
addrlen :是my_addr结构体的长度,可以设置成sizeof(struct sockaddr);
                my_addr :是一个指向sockaddr的指针. 在中有 sockaddr的定义
					struct sockaddr
{ 
    unisgned short as_family;
    char sa_data[14];
};
不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(struct
sockaddr_in) 来代替.在中有sockaddr_in的定义
struct sockaddr_in
{
    						  unsigned short sin_family;		//存放地址协议类型  AF_INET
    unsigned short int sin_port; //存放你要绑定的端口号
    struct in_addr sin_addr;	//存放你要绑定的ip地址
    unsigned char sin_zero[8];	//是用来填充结构体大小的
};
struct in_addr
 {
    in_addr_t s_addr;
 };

     注意:      sin_addr设置为INADDR_ANY表示可以和任何的主机通信,如果需要指定,则自定义IP地址
    
    【返回值】 成功 0 失败 -1 或者其错误码errno
                errno 数值如下:
                    EADDRINUSE :给定地址已经使用
                    EBADF      : sockfd 不合法
                    EINVAL     : sockfd 已经绑定到其他地址
                    ENOTSOCK   : sockfd 是一个文件描述符,不是 socket描述符
                    EACCES     : 地址被保护,用户的权限不足
                    EADDRNOTAVAIL : 接口不存在或者绑定地址不是本地
                    EFAULT :    my_addr指针超出用户空间
                    EINVAL  :  地址长度错误,或者socket不是AF_UNIX族
                    ELOOP   : 解析my_addr是符号链接过多
                    ENAMETOOLONG :my_addr过长
                    ENOENT  :文件不存在
                    ENOMEM :内核内存不足
                    ENOTDIR:不是目录
                    EROFS :socket 节点应该在只读文件系统上
                    
    【注意点】
            1. sockaddr中包含了地址、端口和IP地址的信息。
            2. 在进行地址绑定的时候,需要先将地址结构中的IP地址、端口、类型等
                结构struct sockaddr 中的域进行设置后才能进行绑定,这样绑定后才能将
                套接字文件描述符与地址等结合在一起。
                    
    

                     

3. listen()监听本地端口

【原型】    int listen(int sockfd,int backlog);
    【头文件】 #include <sys/socket.h>
    【功能】 监听本地的端口
    【参数】 sockfd: socket创建的描述符。
             backlog: 表示等待队列的长度
             
    【返回值】 成功 0 ,失败 -1
                其错误码errno如下:
                    EADDRINUSE :另一个socket已经在同一端口侦听。
                    EBADF :参数sockfd不是合法的描述符
                    ENOTSOCK :参数sockfd不是代表socket的文件描述符
                    EOPNOTSUPP :socket不支持listen操作
                    
                    
    【注意点】 1. 在接受一个连接之前,需要用listen()函数来侦听端口
                    listen()函数中参数backlog的参数表示在accept()函数处理之前
                    在等待队列中的客户端的长度,如果超过这个长度,客户端会返回
                    一个ECONNREFUSED错误
                    
                2. listen()函数仅对类型为SOCK_STREAM或者SOCK_SEQPACKET的协议有效
                
                    

4. accept()接受一个网络请求

    【原型】    int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
    【头文件】 #include <sys/types.h> 
                #include <sys/socket.h>
    【功能】    接受一个网络请求
    【参数】    sockfd: 套接字文件描述符
                addr : socket相关数据:IP地址,端口,协议族等信息。
                addrlen :表示第2个参数(addr)所指内容的长度。
    【返回值】 成功:返回新套接字文件描述符。   
                失败: -1 
                错误码errno如下:
                EAGAIN/EWOULDBLOCK :此socket使用了非阻塞模式,当前情况下没有可接受的连接。
                EBADF :描述符非法
                ECONNABORTED :连接取消
                EINTR : 信号在合法连接到来之前打断了accept的系统调用
                EINVAL :socket 没有侦听到连接或者地址长度不合法
                EMFILE :每个进程允许打开的文件描述符数量最大值已经到达
                ENFILE :达到系统允许打开文件的总数量
                ENOTSOCK : 文件描述符是一个文件,不是socket
                EOPNOTSUPP : 引用的socket 不是流类型SOCK_STREAM
                EFAULT :参数addr不可写
                ENOBUFS/ENOMEM :内存不足
                EPROTO :协议错误
                EPERM :防火墙不允许连接。
            
            
   



       

5. connect() 连接目标网络服务器

    【原型】    int connect(int sockfd,struct sockaddr * serv_addr,int addrlen);
    【头文件】 #include <sys/types.h>
                #include <sys/socket.h>
    【功能】    连接目标网络服务器
    【参数】    sockfd : 建立套接字时返回的套件字文件描述符,由系统调用socket()返回的
                serv_addr :是一个指向数据结构sockaddr的指针
                            其中包括客户端需要连接的服务器的目的端口和IP地址以及协议类型。
                addrlen :表示第二个参数内容的大小,可以使用sizeof(sockaddr)    而获得。
    【返回值】 成功 0, 失败-1
                查看错误码errno:
                    EACCES :在AF_UNIX 协议中,使用路径名作为标识符。EACCES 表示目录不可写或者不可访问
                    EADDRINSE :用户没有设置广播标志而连接广播地址或者连接请求被防火墙限制
                    EADDRINUSE :本地地址已经在使用
                    EAFNOSUPPORT :参数serv_addr的域sa_family不正确
                    EAGAIN :本地端口不足
                    EALREADY :socket 是非阻塞类型并且前面的连接没有返回
                    EBADF :文件描述符不是合法的值
                    ECONNREFUSED :连接的主机地址没有侦听
                    EFAULT :socket 是非阻塞模式,而连接不能立刻返回。
                    EINPROGRESS :socket 是非阻塞模式,而连接不能立刻返回
                    EINTR :函数被信号中断
                    EISCONN :socket 已经连接
                    ENETUNREACH :网络不可达
                    ENOTSOCK :文件描述符不是一个socket
                    ETIMEDOUT :连接超时
                    


6. send()通过套接字socket传输数据

【原型】    ssize_t send (int s,const void *msg,size_t len,int flags);
    【头文件】 #include < sys/socket.h >
    【功能】    将数据由指定的 socket 传给对方主机。
    【参数】    s :指定发送端套接字描述符;
                msg :要发送数据的缓冲区;
                len :指明实际要发送的数据的字符数;
                flags : 一般置0
                flags 参数有如下的选择:
                    MSG_DONTROUTE 勿将数据路由出本地网络
                    MSG_DONTWAIT 允许非阻塞操作(等价于使用O_NONBLOCK)
                    MSG_EOR 如果协议支持,此为记录结束
                    MSG_OOB 如果协议支持,发送带外数据
                    MSG_NOSIGNAL 禁止向系统发送异常信息
    【返回值】 成功:返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。
                错误代码errno:
                EBADF 参数 s 非法的 socket 处理代码。
                EFAULT 参数中有一指针指向无法存取的内存空间。
                WNOTSOCK 参数 s 为一文件描述词,非 socket。
                EINTR 被信号所中断。
                EAGAIN 此动作会令进程阻断,但参数 s 的 socket 为不可阻断的。
                ENOBUFS 系统的缓冲内存不足。
                EINVAL 传给系统调用的参数不正确。
                

    【函数说明】
                1. send() 使用 send 时套接字必须已经连接。
                2. send 不包含传送失败的提示信息,如果检测到本地错误将返回-13. 如果send 成功返回,并不必然表示连接另一端的进程接收数据。
                   所保证的仅是当send 成功返回时,数据已经无错误地发送到网络上。
                4. 对于支持为报文设限的协议,如果单个报文超过协议所支持的最大尺寸,
                   send 失败并将 errno 设为 EMSGSIZE ;对于字节流协议,send 会阻塞直到整个数据被传输。
                   
      



7. recv()通过套接字接收数据

    【原型】    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    【头文件】 #include <sys/types.h>
                #include <sys/socket.h>
    【功能】    接收客户端消息
    【参数】    sockfd : 接收端套接字描述符; 
                buf:    指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据; 
                len :   buf的长度; 
                flags: 第四个参数一般置0。
    【返回值】 成功:返回接收到的字节数。另一端已关闭则返回0
                失败返回-1,
                错误码errno: 
                EAGAIN:套接字已标记为非阻塞,而接收操作被阻塞或者接收超时 
                EBADF:sock不是有效的描述词 
                ECONNREFUSE:远程主机阻绝网络连接 
                EFAULT:内存空间访问出错 
                EINTR:操作被信号中断 
                EINVAL:参数无效 
                ENOMEM:内存不足 
                ENOTCONN:与面向连接关联的套接字尚未被连接上 
                ENOTSOCK:sock索引的不是套接字 当返回值是0时,为正常关闭连接;
    
    【函数说明】
                1. recv先等待s的发送缓冲中的数据被协议传送完毕,
                    如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,
                2. 如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,
                3. 如果s接收缓冲区中没有数据或者协议正在接收数 据,那么recv就一直等待,直到协议把数据接收完毕。
                4. 当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中
                5. 协议接收到的数据可能大于buf的长度,所以 在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。
                6. recv函数仅仅是copy数据,真正的接收数据是协议来完成的), recv函数返回其实际copy的字节数。
                7. 如果recv函数在等待协议接收数据时网络中断了,那么它返回08. 默认 socket 是阻塞的 解阻塞与非阻塞recv返回值没有区分,都是 <0 出错 =0 连接关闭 >0 接收到数据大小,
                9. 返回值<0时并且(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)的情况下认为连接是正常的,继续接收。
                10. 只是阻塞模式下recv会阻塞着接收数据,非阻塞模式下如果没有数据会返回,不会阻塞着读,因此需要循环读取)。

          


8. htonl()、htons()大小端字节序转换主机到网络

    
    【原型】    uint32_t htonl(uint32_t hostlong);
                uint16_t htons(uint16_t hostshort);
    【头文件】 #include <arpa/inet.h>
    【功能】    htonl :主机字节序到网络字节序的长整型转换
                htons :主机字节序到网络字节序的短整型转换
    【参数】    hostlong、hostshort:需要转换的变量
    【返回值】 转换后的值




9. ntohl()、ntohs()大小端字节序转换网络到主机

    【原型】    uint32_t ntohl(uint32_t netlong);
                uint16_t ntohs(uint16_t netshort);
    【头文件】 #include<arpa/inet.h>
    【功能】    ntohl:网络字节序到主机字节序的长整型转换
                ntohs:网络字节序到主机字节序的短整型转换
    【返回值】 转换后的值



10. inet_aton()将点分十进制的IP地址转换为二进制IP地址

    【原型】int inet_aton(const char *cp, struct in_addr *inp);
    【头文件】  #include <netinet/in.h>
                 #include <arpa/inet.h>
    【功能】    将cp中存储的点分十进制字符串类型的IP地址转换为
                二进制的IP地址
    【参数】    cp: 点分十进制字符串类型的IP地址
                inp: 指向的结构struct in_addr中。
    【返回值】 成功:非0 失败 0
    
    
   

11. inet_addr()将点分十进制的IP地址转换为二进制IP地址

   【原型】in_addr_t inet_addr(const char *cp);
    【头文件】  #include <netinet/in.h>
                 #include <arpa/inet.h>
    【功能】    将cp中存储的点分十进制字符串类型的IP地址转换为
                二进制的IP地址,IP地址是以网络字节序表达。
    【参数】    cp: 点分十进制字符串类型的IP地址
    【返回值】 成功:转换后的IP地址 失败 -1 
     

12. inet_network()将点分十进制的IP地址转换为二进制IP地址

 【原型】in_addr_t inet_network(const char *cp);
    【头文件】  #include <netinet/in.h>
                 #include <arpa/inet.h>
    【功能】    将cp中存储的点分十进制字符串类型的IP地址转换为
                二进制的IP地址,IP地址是以网络字节序表达的
    【参数】    cp:采用如下形式:
                (1) a.b.c.d : 完全的IP地址转换,此情况下与inet_addr()完全一致
                (2) a.b.c :这种形式指定了IP地址的前3个段,a.b解释为IP地址的前16位
                    c解释为IP地址的后16(3) a.b: 这种形式指定了IP地址的前2个段,a为IP地址的前8,b解释为后面的24位
                        例如:172.888888 会将888888解释为IP地址的后3(4) a:当仅为一部分时,a的值直接作为IP地址,不做字节序转换。
    【返回值】 成功:返回32位表示IP地址 失败 -1
    
    

13. inet_ntoa()将一个地址结构转换为点分十进制的IP地址

    【原型】char *inet_ntoa(struct in_addr in);
    【头文件】  #include <netinet/in.h>
                 #include <arpa/inet.h>
    【功能】    将一个参数in所表示的Internet地址结构转换为点分十进制的
                4 段式字符串IP地址 形式:a.b.c.d
    【参数】    in :Internet地址结构
    【返回值】 成功:转换后的字符串指针 
    【注意】    转换后的字符串指针内存区域为静态的,有可能被覆盖,因此函数并不是线程安全。

14. inet_makeaddr()将网络地址和主机地址合并成IP地址

  【原型】 struct in_addr inet_makeaddr(int net, int host);
    【头文件】  #include <netinet/in.h>
                 #include <arpa/inet.h>
    【功能】    将主机字节序的网络地址net和主机地址host合并成一个网络字节序的IP地址
    【参数】    net :网络地址   
                host :主机地址
    【返回值】 成功:合并成的网络字节序的IP地址


15. inet_lnaof()返回IP地址的主机部分


    【原型】  in_addr_t inet_lnaof(struct in_addr in);
    【头文件】  #include <netinet/in.h>
                 #include <arpa/inet.h>
    【功能】    返回IP地址的主机部分
    【参数】    in : IP地址
    【返回值】 成功:IP地址的主机部分。

16. inet_netof()返回IP地址的网络部分

   【原型】  in_addr_t inet_netof(struct in_addr in);
    【头文件】  #include <netinet/in.h>
                 #include <arpa/inet.h>
    【功能】    返回IP地址的网络部分
    【参数】    in : IP地址
    【返回值】 成功:IP地址的网络部分。 

17. inet_pton()将IP地址转换为二进制类型

    【原型】    int inet_pton(int af, const char *src, void *dst);
    【头文件】 #include <arpa/inet.h>
    【功能】    将字符串类型的IP地址转换为二进制类型
    【参数】    af : 网络类型的协议族,在IPv4下的值为:AF_INET
                src :需要转换的字符串
                dst:指向转换后的结果指针
    【返回值】 成功:正值 失败:
                                0 :src指向的值不是合法的IP地址
                                -1 :通常是af所指定的协议族不支持
                                    此时返回错误码errno :EAFNOSUPPORT

18. inet_ntop()将二进制网络IP地址转换为字符串


    【原型】    int inet_ntop(int af, const char *src, char *dst,socklen_t cnt);
    【头文件】 #include <arpa/inet.h>
    【功能】    将二进制网络IP地址转换为字符串
    【参数】    af : 网络类型的协议族,在IPv4下的值为:AF_INET
                src :需要转换的二进制IP地址 
                在IPv4下src指向struct in_addr结构类型的指针
                dst:指向保存结果缓冲区的指针 
                cnt :是dst缓冲区的大小
    【返回值】 成功:指向dst的指针 
                失败:NULL
                errno :EAFNOSUPPORT :af设定的协议族不支持
                errno :ENOSPC :dst缓冲区大小过小。
                                    
       


19. setsockopt()设置套接字关联的选项

    【原型】    int setsockopt(int socket, int level, int option_name,
                            const void *option_value, socklen_t option_len);
    【头文件】 #include <sys/types.h>
                #include <sys/socket.h>
    【参数】
            1. socket:将要被设置或者获取选项的套接字。
            2. level:选项所在的协议层。
                (1)SOL_SOCKET:通用套接字选项.
                (2)IPPROTO_IP:IP选项.
                (3)IPPROTO_TCP:TCP选项.
            3. option_name:需要访问的选项名。
            
                选项名称        说明                  数据类型
                ========================================================================
                            SOL_SOCKET
                ------------------------------------------------------------------------
                SO_BROADCAST      允许发送广播数据            int
                SO_DEBUG        允许调试                int
                SO_DONTROUTE      不查找路由               int
                SO_ERROR        获得套接字错误             int
                SO_KEEPALIVE      保持连接                int
                SO_LINGER        延迟关闭连接              struct linger
                SO_OOBINLINE      带外数据放入正常数据流         int
                SO_RCVBUF        接收缓冲区大小             int
                SO_SNDBUF        发送缓冲区大小             int
                SO_RCVLOWAT       接收缓冲区下限             int
                SO_SNDLOWAT       发送缓冲区下限             int
                SO_RCVTIMEO       接收超时                struct timeval
                SO_SNDTIMEO       发送超时                struct timeval
                SO_REUSERADDR      允许重用本地地址和端口         int
                SO_TYPE         获得套接字类型             int
                SO_BSDCOMPAT      与BSD系统兼容              int
                ========================================================================
                            IPPROTO_IP
                ------------------------------------------------------------------------
                IP_HDRINCL       在数据包中包含IP首部          int
                IP_OPTINOS       IP首部选项               int
                IP_TOS         服务类型
                IP_TTL         生存时间                int
                ========================================================================
                            IPPRO_TCP
                ------------------------------------------------------------------------
                TCP_MAXSEG       TCP最大数据段的大小           int
                TCP_NODELAY       不使用Nagle算法             int
                ========================================================================
                
            4. option_value:指向包含新选项值的缓冲。
            5. option_len:现选项的长度。
            
    【功能】    获取或者设置与某个套接字关联的选 项。
                选项可能存在于多层协议中,它们总会出现在最上面的套接字层。
                当操作套接字选项时,选项位于的层和选项的名称必须给出。
                为了操作套接字层的选项,应该 将层的值指定为SOL_SOCKET。
                为了操作其它层的选项,控制选项的合适协议号必须给出。
                例如,为了表示一个选项由TCP协议解析,层应该设定为协议 号TCP。
            
    【返回值】  成功:0。失败:-1
                errno被设为以下的某个值:  
                EBADF:sock不是有效的文件描述词
                EFAULT:optval指向的内存并非有效的进程空间
                EINVAL:在调用setsockopt()时,option_len无效
                ENOPROTOOPT:指定的协议层不能识别选项
                ENOTSOCK:sock描述的不是套接字
                
    【注意点】 当设置TCP套接口接收缓冲区的大小时,函数调用顺序是很重要的,
                因为TCP的窗口规模选项是在建立连接时用SYN与对方互换
                得到的。对于客户,O_RCVBUF选项必须在connect之前设置;
                对于服务器,SO_RCVBUF选项必须在listen前设置。



20. getsockopt()获得套接字关联的选项

    【原型】     int getsockopt(int socket, int level, int option_name,
                                void *restrict option_value, socklen_t *restrict option_len);
                                
    【参数】optval:指向返回选项值的缓冲。
            optlen:作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。
            
    【其他值参照setsockopt】

21. sendto()把UDP数据报发给指定地址


    【原型】    ssize_t sendto(int socket, const void *message, size_t length,
                            int flags, const struct sockaddr *dest_addr,
                            socklen_t dest_len);
                            
    【头文件】 #include <sys/socket.h>
    
    【参数】    (1)socket:  正在监听端口的套接口文件描述符
                (2)message: UDP数据报缓存地址。(发送数据缓冲区)
                (3)lenght:  UDP数据报长度。(发送数据缓冲区大小)
                (4)flags:   该参数一般为0(5)dest_addr:      struct sockaddr_in类型,指明UDP数据发往哪里报。
                (6)dest_len:   对方地址长度,一般为:sizeof(struct sockaddr_in)。
                
    
    【返回值】 成功:返回实际传送出去的字符数
                失败返回-1 :错误原因存于errno 中。
				errno:
                EBADF 参数s非法的socket处理代码。
                EFAULT 参数中有一指针指向无法存取的内存空间。
                ENOTSOCK 参数 s为一文件描述词,非socket。
                EINTR 被信号所中断。
                EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断的。
                ENOBUFS 系统的缓冲内存不足。
                EINVAL 传给系统调用的参数不正确。

            

22. recvfrom()从指定地址接收UDP数据报

    【原型】    ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
                                int flags, struct sockaddr *restrict address,
                                socklen_t *restrict address_len);
                                
    【头文件】  #include <sys/socket.h>
    
    【参数】    (1)socket:  socket描述符。
                (2)buffer: UDP数据报缓存地址。
                (3)lenght:  UDP数据报长度。
                (4)flags:   该参数一般为0(5)address: struct sockaddr_in类型,指向本地的数据结构体sockaddr_in的指针,
                            发送数据时发送方的地址信息放在这个结构体中。
                (6)address_len  表示address所指内容的长度,可以使用sizeof(struct sockaddr_in)来获得。
                
    【返回值】 成功:返回收到的数据长度,数据长度可以为0
                失败:返回-1
                发生错误的errno:
				EBADF 参数s非合法的socket处理代码
                EFAULT 参数中有一指针指向无法存取的内存空间。
                ENOTSOCK 参数s为一文件描述词,非socket。
                EINTR 被信号所中断。
                EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断。
                ENOBUFS 系统的缓冲内存不足
                ENOMEM 核心内存不足
                EINVAL 传给系统调用的参数不正确。


19-21-22代码演示:

————————————————————————————————————————————————————————————

客户端:

#include "myhead.h"//这个头文件里面已经将常用函数的头文件全部包含了
/*
   演示udp广播发送端
*/
int main()
{
    int udpsock;
    int ret;
    char buf[20];
    struct sockaddr_in destaddr;
    bzero(&destaddr,sizeof(destaddr));
    destaddr.sin_family=PF_INET;
    destaddr.sin_port=htons(10000);
    //使用广播地址
    inet_aton("192.168.110.255",&(destaddr.sin_addr));
    
    udpsock=socket(PF_INET,SOCK_DGRAM,0);//创建数据报套接字
    if(udpsock==-1)
    {
        perror("创建udp失败!\n");
        return -1;
    }
    //设置套接字的属性为可以广播
    int on = 1;
    ret=setsockopt(udpsock,SOL_SOCKET,SO_BROADCAST, &on, sizeof(on));
    if(ret==-1)
    {
        perror("设置广播失败!\n");
        return -1;
    }
    //广播发送信息 
    bzero(buf,20);
    printf("请输入你要广播发送的内容!\n");
    fgets(buf,20,stdin);
    ret=sendto(udpsock,buf,20,0,(struct sockaddr *)&destaddr,sizeof(destaddr));
    printf("sendto返回值是:%d\n",ret);
}


服务端:


#include "myhead.h"//这个头文件里面已经将常用函数的头文件全部包含了
/*
   演示udp广播接收端
*/
int main()
{
    int udpsock;
    int ret;
    int addrsize=sizeof(struct sockaddr);
    char buf[20];
    struct sockaddr_in bindaddr;
    struct sockaddr_in souraddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=PF_INET;
    bindaddr.sin_port=htons(10000);
    bindaddr.sin_addr.s_addr=htonl(INADDR_ANY);//注意
    
    udpsock=socket(PF_INET,SOCK_DGRAM,0);//创建数据报套接字
    if(udpsock==-1)
    {
        perror("创建udp失败!\n");
        return -1;
    }
    //绑定
    ret=bind(udpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
    if(ret==-1)
    {
        perror("绑定失败!\n");
        return -1;
    }
    //接收信息 
    bzero(buf,20);
    ret=recvfrom(udpsock,buf,20,0,(struct sockaddr *)&souraddr,&addrsize);
    printf("recvfrom返回值是:%d  %s\n",ret,buf);
}


————————————————————————————————————————————————————————————




   

23. select()监视文件描述符的状态

    【原型】    int select(int nfds, fd_set *restrict readfds,
                          fd_set *restrict writefds, fd_set *restrict errorfds,
                          struct timeval *restrict timeout);
                          
    【头文件】 #include <sys/select.h>
    【功能】    监视多个文件描述符的集合,判断是否有符合条件的时间发生。
    
    【参数】    nfds: 比所有文件描述符集合中的文件描述符的最大值大1的变量
                readfds :监测文件描述符集合中的任意一个文件是否有数据可读。
                writefds: 监测文件描述符集合中的任意一个文件是否有数据可写。
                errorfds : 监测文件集中的任何文件是否发生错误
                timeout : 超时等待时间(最长的等待时间),当超过此时间时,函数会返回。
                struct timeval
                        {
                            time_t tv_sec;  /*秒*/
                            long tv_usec;   /*微秒*/
                        };
                
    【返回值】 1. 超时返回 0
                2. 文件描述符符合要求 :返回大于 0 的正值
                        (1)读文件描述符集中的文件可读
                        (2)写文件描述符集中的文件可写
                        (3)错误文件描述符中的文件发生错误
                        
                3. 返回值为 -1 :发生了错误,错误码errno如下:
                        (1) EBADF :参数s不是合法描述符
                        (2) EINTR :接收到中断信号
                        (3) EINVAL : 传递了不合法参数
                        (4) ENOMEM :没有足够内存
                
                
    【注意点】 1. nfds在使用之前必须计算最大值的文件描述符的值,才能将其值写入进nfds
                2. readfds 当select()函数返回的时候,将清除其中不可读的文件描述符,只留下可读的文件描述符
即可以被recv(),read()等进行数据的操作。
                3. writefds 当select()函数返回的时候,readfds将清除其中的不可写的文件描述符,只留下可写的文件描述符
即可以被send()write()函数等进行写数据的操作。
                4. errorfds还可以监视外数据OOB,当select函数返回的时候,readfds将清除其中的其他文件描述符,只留下可读OOB数据
                5. 当 timeout 设置为NULL的时候,表示阻塞操作,会一直等待,直到某个监视的文件集中的某个文件描述符符合返回条件。
                   当timeout为0的时候,函数会立即返回
                   
                6. 函数select()允许程序监视多个文件描述符,当一个或者多个文件描述符准备就绪,可以进行IO操作的时候返回。
    
    
    【返回值】 1. 超时返回 0
                2. 文件描述符符合要求 :返回大于 0 的正值
                        (1)读文件描述符集中的文件可读
                        (2)写文件描述符集中的文件可写
                        (3)错误文件描述符中的文件发生错误
                        
                3. 返回值为 -1 :发生了错误,错误码errno如下:
                        (1) EBADF :参数s不是合法描述符
                        (2) EINTR :接收到中断信号
                        (3) EINVAL : 传递了不合法参数
                        (4) ENOMEM :没有足够内存

                        
                      

24. pselect()监听文件描述符的状态

   【原型】    int pselect(int nfds, fd_set *restrict readfds,
                              fd_set *restrict writefds, fd_set *restrict errorfds,
                              const struct timespec *restrict timeout,
                              const sigset_t *restrict sigmask);

                          
    【头文件】 #include <sys/select.h>
    【功能】    监视多个文件描述符的集合,判断是否有符合条件的时间发生。
    
    
    【参数】    nfds: 比所有文件描述符集合中的文件描述符的最大值大1的变量
                readfds :监测文件描述符集合中的任意一个文件是否有数据可读。
                writefds: 监测文件描述符集合中的任意一个文件是否有数据可写。
                errorfds : 监测文件集中的任何文件是否发生错误
                timeout : 超时等待时间(最长的等待时间),当超过此时间时,函数会返回。
                    struct timeval
                            {
                                long tv_sec;        /*超时的秒数*/
                                long tv_nsec;       /*超时纳秒数*/
                            };
                signask :替换掉的信号处理方式,为NULL与select一样。
                


25. FD文件描述符号集的操作宏(并非函数)

    【宏1void FD_CLR(int fd, fd_set *fdset);
      【功能】  用来将一个给定的文件描述符从集合中删除
    
      【宏2int FD_ISSET(int fd, fd_set *fdset);
      【功能】  检测fd在sdset集合中的状态是否变化,当检测到状态发生变化的时候返回真(0),否则返回假0
      【返回值】   真:非0 
                    假: 0
      【宏3void FD_SET(int fd, fd_set *fdset);
      【功能】  用来将一个给定的文件描述符加入集合中
      
      【宏4void FD_ZERO(fd_set *fdset);
      【功能】  用来清空fd_set集合。
      
      【参数】  fd :文件描述
                fdset :文件描述符集。
      

26. poll() 等待某个文件描述符上的某个事件的发生

    【原型】    int poll(struct pollfd *fds,nfds_t nfds,int timeout);
    【头文件】 #include <poll.h>
    【功能】    检测文件描述符的状态
    【参数】    (1) fds :是一个数组,存放的是一组要监测的文件描述符
                (2) nfds :是比监视的最大描述符的值大1的值
                (3) timeout :是超时时间,单位为毫秒,当为负值的时表示永远等待。
                struct pollfd
                {
                    int fd; //文件描述符
                    short event; //请求的时间
                    short revents; //返回的事件 
                }
                event与revents的监视事件
                POLLIN:有数据到来,文件描述符可读
                POLLPRI :有紧急数据可读,例如带外数据
                POLLOUT : 文件可写
                POLLRDHUP : 流式套接字半关闭
                POLLERR : 错误发生
                POLLHUP :关闭
                POLLNVAL : 非法请求
                POLLRDNORM : 与POLLIN相同
                POLLRDBAND :优先数据可读
                POLLWRNORM : 与POLLOUT 相同
                POLLWRBAND : 优先数据可写
                
    【返回值】 成功:大于0 (等待的某个条件满足,返回值为满足条件的监视文件描述符的数量)
                失败: 0 表示超时
                       -1; 表示发生错误,errno的错误代码表:
                        EBADF:参数S不是合法描述符
                        EINTR: 接收到中断信号 
                        EINVAL: 传递了不合法的参数
                        ENOMEM: 没有足够内存


发布了9 篇原创文章 · 获赞 10 · 访问量 280

猜你喜欢

转载自blog.csdn.net/my___sunshine/article/details/103999638
今日推荐