当前位置: 代码迷 >> 综合 >> 2022-3-1
  详细解决方案

2022-3-1

热度:121   发布时间:2023-10-14 11:27:21.0

2022-3-1

  • select
    • select的相关函数
      • 网络字节序转换
    • 实现

select

2022-3-1
select、poll、epoll都是实现io多路复用的手段
select函数有5个参数
int nfds:表示管理的数量,例如下图中就应该为8
2022-3-1
fd_set *readfds:表示应当监听的会发生读操作的文件的文件描述符集合,例如c1用户发送连接请求,这时lfd就会收到c1发来的请求,于是lfd,也就是文件3就会发生读操作

fd_set *writefds:表示应当监听的会发生写操作的文件的文件描述符集合

fd_set *exceptfds:表示应当监听的会发生异常的文件的文件描述符集合

上述三个文件描述符集合,传入的时候是我们想要监听的文件描述符,传出的时候是发生了对应事件的文件描述符,例如上图,读操作的文件描述符,传入的时候在3、5、6上都是1,其他都是0,select执行完后,就只有5、6是1了,因为3没有发生读操作

struct timeval *timeout:表示监听的持续时间

返回值代表了所有监听集合中发生的事件的综述,上图就是3

文件描述符集合就是上图右下角那种类似数组的东西,里面存的0或1

select的相关函数

2022-3-1
这些函数是对文件描述符集合进行操作的

使用上图监听读操作的3、5、6,写操作的4、6,异常的7进行解释

void FD_ZERO(fd_set *set):清空一个文件描述符集合

fd_set rset;
FD_ZERO(&rset);

void FD_SET(int fd, fd_set *set):将待监听的文件描述符,添加到集合中

FD_SET(3, &rset);
FD_SET(5, &rset);
FD_SET(6, &rset);

void FD_CLR(int fd, fd_set *set):将一个文件描述符从监听集合中移除
例如用户c1结束了与服务器的连接

FD_CLR(4, &rset);

int FD_ISSET(int fd, fd_set *set):判断一个文件描述符是否在监听集合中
返回值:在的话是1,不在是0

网络字节序转换

由于历史遗留问题,我们计算机端的字节序是按小端法存储的,也即高位存高地址,低位存低地址,而网络中(IP协议)是按大端法存储的,与小端法刚好相反,于是就有用于字节序转换的函数
2022-3-1
2022-3-1
但是由于我们一般使用的是点存十进制的IP地址,例如192.168.1.1,他本质是一个string,而函数要一个uint32,很麻烦,所以一般使用一个封装好的函数
2022-3-1
INADDR_ANY表示获取本机上任意一个能使用的ip

2022-3-1
af:当前使用的IP协议----AF_INET(ipv4)、AF_INET6(ipv6)
src:点存十进制的ip地址
dst:转换后的网络字节序
return 1代表转换成功,0代表失败

实现

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<ctype.h>int main(int argc, char *argv[]){
    int i,n,j;int listenfd,connfd;char buf[BUFSIZ];struct sockaddr_in clie_addr, serv_addr;socklen_t clie_addr_len;listenfd = socket(AF_INET, SOCK_STREAM, 0);int opt=1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(&serv_addr,sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port = htons(9527);bind(listenfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));listen(listenfd,128);fd_set rset,allset;FD_ZERO(& allset);FD_SET(listenfd, &allset);int ret,maxfd=listenfd;while(1){
    rset=allset;ret = select(maxfd+1, &rset, NULL, NULL, NULL, 10);if(FD_ISSET(listenfd, &rset){
    clie_addr_len = sizeof(clie_addr);connfd = accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len);FD_SET(connfd, &allset);if(maxfd<connfd)maxfd=connfd;if(ret==1)continue;}for(i=listenfd+1; i<=maxfd; ++i){
    if(FD_ISSET(i, &rset){
    n= read(i,buf,sizeof(buf));if(n==0){
    close(i);FD_CLR(i,&allset);}for(j=0; j<n; ++j){
    buf[j]=toupper(buf[j]);}write(i, buf, n);}}}
}