linux C语言函数API--网络编程函数
程序员文章站
2024-01-21 21:04:58
...
五:网络编程函数
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 不包含传送失败的提示信息,如果检测到本地错误将返回-1。
3. 如果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函数在等待协议接收数据时网络中断了,那么它返回0。
8. 默认 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文件描述符号集的操作宏(并非函数)
【宏1】 void FD_CLR(int fd, fd_set *fdset);
【功能】 用来将一个给定的文件描述符从集合中删除
【宏2】 int FD_ISSET(int fd, fd_set *fdset);
【功能】 检测fd在sdset集合中的状态是否变化,当检测到状态发生变化的时候返回真(非0),否则返回假0
【返回值】 真:非0
假: 0
【宏3】 void FD_SET(int fd, fd_set *fdset);
【功能】 用来将一个给定的文件描述符加入集合中
【宏4】 void 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: 没有足够内存
下一篇: linux系统下的fopen函数