Linux下的http高并发服务器

//简单的高并发服务器端,实现多个客户端的连接与数据处理(聊天)
//TCP服务器端程序
//1.新连接的描述符会覆盖,因此需要一个数组保存
//2.将监听socket描述符添加到数组中
//3.定义一个select可读时间描述符
//4.将数组中可用的描述符全添加到集合中,并选择出最大的描述符
//5.定义一个select等待的超时时间
//6.select开始监控描述符的状态改变
//  1.出错返回
//  2.超时返回
//  3.代表有对象可读,但是我们不知道哪一个描述符可读
//      但是select返回之前干了一件事,将没有就绪的描述符从集合中移除                                                                 
//      意味着现在集合中存在的描述符都是就绪的描述符
//  4.现在判断数组中的哪一个描述符还继续在集合中,如何在,就代表这个描述符是就绪状态的
//      1.如果这个就绪的描述符是监听描述符,代表有新连接,接收连接
//      2.如果不是,代表有数据到来,接收数据
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>

int main(int argc, char *argv[])
{
        if(argc != 3) {
                printf("Usage : ./a.out ip port\n");
        }
        //多个描述符,需要一个数组
        int lis_fd, cli_fd;
        int i, ret;
        socklen_t len;
        struct sockaddr_in lis_addr;
        struct sockaddr_in cli_addr;
        int fd_list[1024];
        struct timeval tv;
        tv.tv_sec = 3;
        tv.tv_usec = 0;
        fd_set readfds;

        lis_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(lis_fd < 0) {
                perror("socket error");
                return -1;
        }

        lis_addr.sin_family = AF_INET;
        lis_addr.sin_port = htons(atoi(argv[2]));   
        lis_addr.sin_addr.s_addr = inet_addr(argv[1]);
        len = sizeof(struct sockaddr_in);
        ret = bind(lis_fd, (struct sockaddr*)&lis_addr, len);
        if(ret < 0) {
            perror("serv bind");
            return -1;
        }

        if(listen(lis_fd, 5) < 0) {
                perror("listen");
                return -1;
        }

        for(i = 0; i < 1024; i++) {
                fd_list[i] = -1;
        }

        fd_list[0] = lis_fd;
        int max_fd = lis_fd;
        while(1) {
                //清空集合
                FD_ZERO(&readfds);
                //将所有的fd都添加到集合当中
                for(i = 0; i < 1024; i++) {
                        if(fd_list[i] != -1) {
                                FD_SET(fd_list[i], &readfds);     
                                 FD_SET(fd_list[i], &readfds);
                        }

                        //从所有的描述符中找到最大的描述符
                        if(fd_list[i] > max_fd) {
                                max_fd = fd_list[i];
                        }
                }


                //select 开始监控描述符集合中是否就绪
                tv.tv_sec = 3;
                tv.tv_usec = 0;
                ret = select(max_fd + 1, &readfds, NULL, NULL, &tv);
                if(ret < 0) {
                        perror("select error");
                        continue;
                } else if(ret == 0) {
                        printf("timeout\n");
                        continue;
                }

                //走到这一步代表有描述符就绪(有数据到来), 但是不知道到底是哪一个描述符
                //因此需要循环去判断fd列表中哪一个可读
                for(i = 0; i < 1024; i++) {
                        if(fd_list[i] < 0) continue;   
                         //判断哪个描述符就绪了
                        if(FD_ISSET(fd_list[i], &readfds)) {
                                //如果就绪的描述符是监听描述符就要接受
                                if(fd_list[i] == lis_fd) {
                                        cli_fd = accept(lis_fd, (struct sockaddr*)&cli_fd, &len);
                                        if(cli_fd < 0) {
                                                continue;
                                        }
                                        for(i = 0; i < 1024; i++) {
                                                if(fd_list[i] == -1) {
                                                        fd_list[i] = cli_fd;
                                                        break;
                                                }
                                        }
                                } else {
                                        //如果就绪的描述符不是监听描述符,代表有客户端连接的数据
                                        char buff[1024] = {0};
                                        ret = recv(fd_list[i] , buff, 1023, 0);
                                        if(ret <= 0) {
                                                close(fd_list[i]);
                                                fd_list[i] = -1;
                                        }
                                        printf("client say : %s\n", buff);
                                        send(fd_list[i], "what fuck!!!\n", 12, 0);
                                }
                        }
                }
        }
        return 0;
}                                                                                                                                    
                                                        

猜你喜欢

转载自blog.csdn.net/IronMan240/article/details/81779436