#include <sys/select.h>
#include <sys/times.h>
void server101() {
    int serv_sock = socket(PF_INET, SOCK_STREAM, 0), clnt_sock;
    sockaddr_in serv_adr, clnt_adr;
    socklen_t clnt_sz = sizeof(sockaddr_in);
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(9527);
    int optval = 1;
    setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(sockaddr_in));
    if (bind(serv_sock, (sockaddr*)&serv_adr, sizeof(sockaddr_in)) == -1) {
        printf("bind error %d %s\n", errno, strerror(errno));
        close(serv_sock);
        return;
    }
    if (listen(serv_sock, 5) == -1) {
        printf("listen error %d %s\n", errno, strerror(errno));
        close(serv_sock);
        return;
    }
    fd_set reads,copy_reads;
    FD_ZERO(&reads);//设置文件描述符1
    FD_SET(serv_sock, &reads);//指定监视范围1
    timeval timeout = { 0,100 };//设置超时1
    int max_sock = serv_sock;
    while (true) {
        copy_reads = reads;
        int fd_num = select(max_sock + 1, ©_reads, NULL, NULL, &timeout);//调用select函数2
        if (fd_num <= -1) {
            printf("select error %d %s\n", errno, strerror(errno));
            close(serv_sock);
            return;
        }
        if (fd_num == 0)continue;
        for (int i = 0; i < max_sock + 1; i++) {//保证max_sock是最大的
            if (FD_ISSET(i, ©_reads)) {//查看调用结果3
                //轮询的对象存在
                if (i == serv_sock) {//是服务器的套接字
                    clnt_sock = accept(serv_sock, (sockaddr*)&clnt_adr, &clnt_sz);//accept()返回值后一次默认比前一次多一
                    FD_SET(clnt_sock, &reads);
                    if (max_sock < clnt_sock) {
                        max_sock = clnt_sock;//更新最大的
                    }                    
                    printf("client is connectd:%d\n", clnt_sock);
                }
                else{//是客户端的轮询
                    sleep(2);
                    char buf[256];
                    ssize_t strlen = read(i, buf, sizeof(buf));
                    if (strlen == 0) {
                        FD_CLR(i, &reads);
                        close(i);
                        printf("client is disconnect:%d\n", i);
                    }
                    else {
                        write(i, buf, strlen);
                        std::cout << "send clent message:" << buf << std::endl;
                    }
                }
            }
        }
    }
    close(serv_sock);
}
void client101()
{
    int sock = socket(PF_INET, SOCK_STREAM, 0);
    sockaddr_in serv_adr;
    socklen_t clnt_sz = sizeof(sockaddr_in);
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_adr.sin_port = htons(9527);
    if (connect(sock, (sockaddr*)&serv_adr, clnt_sz)) {
        printf("connect error %d %s\n", errno, strerror(errno));
        close(sock);
        return;
    }
    char message[256]{};
    while (true) {
        printf("Inpus message:(q to quit):");
        fgets(message, sizeof(message), stdin);
        if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))  break;
        ;
        write(sock, message, strlen(message));        
        memset(message, 0, sizeof(message));
        ssize_t str_len = read(sock, message, sizeof(message));
        message[str_len] = 0;
        std::cout << "recv server:" << message << std::endl;
    }
    close(sock);
}
void lession101(const char* arg)
{
    if (strcmp(arg, "s") == 0) {
        server101();
    }
    else
    {
        client101();
    }
}
int main(int argc,char *argv[])//运行参数s表示启动服务端
{
    lession101(argv[1]);
}