Linux操作系统之网络编程(套接字)select与epoll的区别。

一、套接字
基本特点:socket是一种接口技术,被抽象成一个文件操作,可以让进程之间通信,也可以让不同计算机的进程通信(网络)。

int socket(int domain, int type, int protocol);
功能:创建套接字
domain:
AF_UNIX/AF_LOCAL 本地通信,进程间通信
AF_INET 基于IPv4地址通信
AF_INET6 基于IPv6地址通信
type:
SOCK_STREAM 数据流协议
SOCK_DGRAM 数据报协议
protocol:特殊通信协议,一般不用,写0即可。
返回值:成功返回套接字描述符,失败返回-1。

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定socket和地址(文件路径或网络地址)
sockfd:socket描述符
addr:地址结构体
// 基本地址类型
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
// 本地地址类型 #include <sys/un.h>
struct sockaddr_un{
sa_family_t sun_family; // 地址簇
char sun_path[108]; // socket文件路径
};
// 网络地址类型 #include <netinet/in.h>
struct sockaddr_in{
sa_family_t sin_family; // 地址簇
in_port_t sin_port; // 端口号
struct in_addr sin_addr;// IP地址
};
struct in_addr{
in_addr_t s_addr;
}
addrlen:地址结构体的字节数
返回值:成功返回0,失败返回-1。

int listen(int sockfd, int backlog);
功能:监听socket,数据流通信时使用
sockfd:socket描述符
backlog:排队数量
返回值:成功返回0,失败返回-1。

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:连接socket
sockfd:socket描述符
addr:目标地址
addrlen:地址的字节数
返回值:成功返回0,失败返回-1。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:等待连接
sockfd:socket描述符
addr:获取连接者的地址
addrlen:既输入双输出
既告诉accept函数当前系统地址结构体的字节数,同时也获取发者地址结构体的字节数
返回值:返回一个建议连接后的socket描述符

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:从socket读取数据,数据流通信时使用
sockfd:建立连接后的socket描述符
buf:存储数据的缓冲区地址
len:缓冲区的字节数
flags: 一般写0即可
MSG_OOB 优先接收外带数据
MSG_DONTWAIT 不阻塞
返回值:接收到的字节数,-1出现错误,0连接断开。

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:向socket发送数据,数据流通信时使用
sockfd:建立连接后的socket描述符
buf:待发送的数据首地址
len:要发送的字节数
flags:一般写0即可
MSG_OOB 优先紧急数据
MSG_DONTWAIT 不阻塞
返回值:成功发送的字节数,出错返回-1。

int close(int fd);
功能:关闭socket

TCP网络通信编程模型:
    计算机S                 计算机C
    创建套接字              创建套接字
    准备通信地址(自己的)     准备通信地址(计算机S,与C在同一局域网或S是公用IP)
    绑定套接字和地址         连接计算S
    监听                    ...
    等待连接                ...
    接收/发送数据           发送/接收数据 
    关闭套接字              关闭套接字

多路复用:
由于为了实现服务器的并发(同时服务多个客户端),需要为每个客户端创建一个进程来为它服务,但创建进程、销毁进程非常浪费时间与资源,这个问题有两种解决方案:
1、多路复用:一个进程监控所有的客户端fd+服务端fd。
2、多线程:为每个客户端创建一个线程进行服务。

由于有些读写函数需要以阻塞状态调用,同时可能有多个文件描述需要同时读写,多路复用就是同时监控多个文件的描述符。

int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval timeout);
功能:监控若干个文件描述符
nfds:最大的文件描述符加1
readfds:需要监控读操作的文件描述符集合,既输入又是输出。
writefds:需要监控写操作的文件描述符集合,既输入又是输出。
exceptfds:需要监控异常的文件描述符时间,既输入又是输出。
timeout:倒计时时间
struct timeval {
long tv_sec; /
seconds /
long tv_usec; /
microseconds */
};

void FD_CLR(int fd, fd_set *set);
功能:从集合中删除fd

int FD_ISSET(int fd, fd_set *set);
功能:测试集合是否有fd存在

void FD_SET(int fd, fd_set *set);
功能:向集合中添加文件描述符

void FD_ZERO(fd_set *set);
功能:清空文件描述符

int epoll_create(int size);
功能:创建epoll对象
size:epoll对象的大小,因为内核会自动调整epoll对象的大小,因此该参数目前已经作废。
返回值:epoll对象的描述符

int epoll_ctl(int epfd, int op, int fd, struct epoll_event event);
功能:操作epoll对象,可以添加、删除文件描述符
epfd:epoll对象描述符
op:
EPOLL_CTL_ADD 添加文件描述符
EPOLL_CTL_MOD 修改文件描述符的监控事件
EPOLL_CTL_DEL 删除文件描述符
fd:
要操作的文件描述符
event:
struct epoll_event {
uint32_t events; /
Epoll events /
EPOLLIN 读事件
EPOLLOUT 写事件
epoll_data_t data; /
User data variable */
};

int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
功能:监控epoll对象中的文件描述符
epfd:epoll对象
events:保存发生事件的文件描述符集合
maxevents:最多保存多少个文件描述符
timeout:等待时间,1000/1秒,-1则一直等待。
返回值:事件发生手文件描述符个数

常考面试题:select与epoll的区别。
select和epoll属于I/O多路复用模型,用于持续监听多个socket,获取其IO事件。

select(轮询)

该模型轮询各socket,不管socket是否活跃,随着socket数的增加,性能逐渐下降
调用时轮询一次所有描述字,超时时再轮询一次。如果没有描述字准备好,则返回0;中途错误返回-1;有描述字准备好,则将其对应位置为1,其他描述字置为0,返回准备好的描述字个数。
fd_set:整数数组,每个数中的每一位对应一个描述字,其具体大小有内核的FD_SETSIZE决定,默认值为1024。
epoll(触发)

epoll采用了中断注册回调的方式,socket IO就绪时发出中断,然后将socket加入就绪队列。由三个系统调用:epoll_create,epoll_ctl,epoll_wait。

能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率:它会复用文件描述符集合来传递结果,不需要每次等待事件之前都重新准备要被侦听的文件描述符集合;获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合。

select/epoll都需要在内核和用户空间之间复制数据,epoll使用了内存映射(mmap)技术,将内核和用户空间指向同一块内存。
对比:
select - 如果同时建立很多连接,但只有少数事件发生,这种轮询会造成效率很低;频繁从内核拷贝、复制描述字;监听描述字受限于内核的FD_SETSIZE;
epoll - 这种回调触发式操作会保证效率;不需要频繁的拷贝;监听描述字没有限止,只与系统资源有关;epoll返回时已经明确的知道哪个sokcet fd发生了事件,不用再一个个比对。

本地字节序与网络字节序转换:
uint32_t htonl(uint32_t hostlong);
功能:把4字节的本地字节序数据转换成网络字节序

uint16_t htons(uint16_t hostshort);
功能:把2字节的本地字节序数据转换成网络字节序

uint32_t ntohl(uint32_t netlong);
功能:把4字节网络字节序数据转换成本地字节序

uint16_t ntohs(uint16_t netshort);
功能:把2字节网络字节序数据转换成本地字节序

IPv4地址转换:
int inet_aton(const char *cp, struct in_addr *inp);
功能:把点十进制的IP地址转换成 struct sockaddr_in中的sin_addr成员类型。

in_addr_t inet_addr(const char *cp);
功能:把点十进制的IP地址转换成 struct sockaddr_in中的sin_addr.s_addr,通过返回值返回。

in_addr_t inet_network(const char *cp);
功能:把点十进制的IP地址转换成,转换成本地字节序的二进制。

char *inet_ntoa(struct in_addr in);
功能:struct sockaddr_in中的sin_addr成员转换成点分十进制的ip地址。

struct in_addr inet_makeaddr(int net, int host);
功能:把网络地址与主机地址合并成IP地址

in_addr_t inet_lnaof(struct in_addr in);
功能:计算IP地址的主机地址
ip & ~掩码

in_addr_t inet_netof(struct in_addr in);
功能:计算IP地址的网络地址
ip & 掩码

UDP网络通信:
UDP是无连接的通信协议,准备好地址之后可以直接发送或接收数据。

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:发送数据
sockfd:发送者的socket描述符
buf:待发送的数据
len:数据的长度
flags:一般写0即可。
dest_addr:目标地址
addrlen:地址的长度
返回值:成功发送的数据的字节数

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据
sockfd:接收者的socket描述符
buf:存储数据的缓冲区
len:缓冲区的长度
flags:一般写0即可
src_addr:存储发送者的地址
addrlen:既是输入(当前系统地址的字节数)也是输出(获取发送者地址的字节数),存储发送者地址的长度。
返回值:成功接收到的数据的字节数。

UDP网络通信编程模型:
    计算机S                 计算机C
    创建socket对象          创建socket对象
    准备通信地址            准备通信地址(S的地址)
    绑定socket对象和地址    
    接收/返回数据           发送/接收数据
    关闭socket对象          关闭socket对象

UDP广播通信:
广播就是发送者发出一条数据,路由器把这条数据向局域网中的所有计算转发一次。
如何广播:就是向一个特殊地址发送数据,同时还要设置sock对象的属性。
广播地址就是除了网络地址其它位全为1。
192.168.0.113
255.255.255.0
192.168.0 网络地址
113 主机地址
192.168.0.255 广播地址

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
功能:设置socket对象的属性
sockfd:socket对象的描述符
level:要设置的协议层
SOL_SOCKET
SO_BROADCAST 广播
IPPROTO_IP
IP_MULTICAST_TTL 多播
IPPROTO_TCP
optname:要设置的选项名
optval:存储要修改的值的缓冲区
optlen:缓冲区的长度

int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值