linux下的高并发的TCP状态转换----select

1.I/O的操作方式

(1)阻塞等待

(2)解决办法

2.I/O口多路转换技术:

(1)先构造一张有关于文件描述符的列表,将要监听的文件描述符加入到其中

(2)调用一个函数,监听该表中的文件描述符,然后看表中哪一个文件描述符在进行I/O端口的操作,该函数才返回。该函数是阻塞函数,需要调用部分内存实现

3.I/O口多路转换---select

(2)文件描述符操作函数

●全部清空

void FD_ZERO(fd_set *set);

●删除其中的一项

void FD_CLR(int fd,fd_set *set);

●将某个文件描述符加到集合里面

void FD_SET(int fd,fd_set *set);

●判断某个文件描述符是否在集合里

void FD_ISSET(int fd,fd_set *set);

3.select函数的实例:

/*服务端*/

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 80
#define SERV_PORT 8000
 int main(int argc, char *argv[]){
     int i, maxi, maxfd, listenfd, connfd, sockfd;
     //client 自定义数组,遍历上限值
     int nready, client[FD_SETSIZE]; /* FD_SETSIZE 默认为 1024 */
     ssize_t n;
     //用到的集合,暂存的作用
     fd_set rset, allset;//保存原来的样子  
     char buf[MAXLINE];
     char str[INET_ADDRSTRLEN]; /* #define INET_ADDRSTRLEN 16 */
     socklen_t cliaddr_len;
     struct sockaddr_in cliaddr, servaddr;
     listenfd = Socket(AF_INET, SOCK_STREAM, 0);
     bzero(&servaddr, sizeof(servaddr));
     servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
     Listen(listenfd, 20); /* 默认最大128 */
     maxfd = listenfd; /* 初始化 */
    maxi = -1; /* client[]的下标 */
     for (i = 0; i < FD_SETSIZE; i++)
    client[i] = -1; /* 用-1初始化client[] */
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset); /* 构造select监控文件描述符集 */
///////////////////////描述是否有客户端连接    
     for ( ; ; ) {
     //rect 是
    rset = allset; /* 每次循环时都从新设置select监控信号集 */
    nready = select(maxfd+1, &rset, NULL, NULL, NULL);
    if (nready < 0)
    perr_exit("select error");
     //是哪个要连接
    if (FD_ISSET(listenfd, &rset)) { /* new client connection */
        cliaddr_len = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);//直接调用accpet,不会堵塞
        printf("received from %s at PORT %d\n",
        inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
        ntohs(cliaddr.sin_port));
        //监听的时候加到自定义的集合中去,找到任意一个为-1的塞进去
        for (i = 0; i < FD_SETSIZE; i++)
        if (client[i] < 0) {
        client[i] = connfd; /* 保存accept返回的文件描述符到client[]里 */
        break;
        }
        /* 达到select能监控的文件个数上限 1024 */
        if (i == FD_SETSIZE) {
        fputs("too many clients\n", stderr);
        exit(1);
        }
        FD_SET(connfd, &allset); /* 添加一个新的文件描述符到监控信号集里 */
        if (connfd > maxfd)
        maxfd = connfd; /* select第一个参数需要 */
        if (i > maxi)
        maxi = i; /* 更新client[]最大下标值 ,判断数组是否满了*/
        if (--nready == 0)//设置返回出来的总数
        continue; /* 如果没有更多的就绪文件描述符继续回到上面select阻塞监听,负责处理未
        处理完的就绪文件描述符 */
                }
////////////////////////读数据用的                
        for (i = 0; i <= maxi; i++) { /* 检测哪个clients 有数据就绪 */
        if ( (sockfd = client[i]) < 0)//判断是否赋值成功
        continue;
        if (FD_ISSET(sockfd, &rset)) {
        if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
        /* 当client关闭链接时,服务器端也关闭对应链接 */
        Close(sockfd);
        FD_CLR(sockfd, &allset); /* 解除select监控此文件描述符 */
        client[i] = -1;
        } else {
        int j;
        for (j = 0; j < n; j++)
        buf[j] = toupper(buf[j]);//小写转大写
        Write(sockfd, buf, n);
        }
        if (--nready == 0)
        break;
        }
        }
        }
        close(listenfd);
        return 0;
        }
            

/*客户端*/

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
        struct sockaddr_in servaddr;
        char buf[MAXLINE];
        int sockfd, n;
        sockfd = Socket(AF_INET, SOCK_STREAM, 0);
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
        servaddr.sin_port = htons(SERV_PORT);
        Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
        while (fgets(buf, MAXLINE, stdin) != NULL) {
        Write(sockfd, buf, strlen(buf));
        n = Read(sockfd, buf, MAXLINE);
        if (n == 0)
        printf("the other side has been closed.\n");
        else
        Write(STDOUT_FILENO, buf, n);
        }
        Close(sockfd);
        return 0;
}

 运行结果:

猜你喜欢

转载自www.cnblogs.com/ylq0824/p/10883854.html