linux 网络编程(select)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>


typedef struct{
    int *fd;        //文件描述符数组
    int count;      //数组元素个数
    int max_count;  //fd对应空间大小
}st_fd_def;


/*
    将fd接收套接字描述符放入到fd数组中
*/
int add_fd(st_fd_def* p_st_fd, int fd)
{
    int i  = 0;
    /*
        校验当前文件描述符个数等于最大分配空间时
        重新申请新的fd大小+3
    */
    if (p_st_fd->count == p_st_fd->max_count)
    {
        int *p_fd = (int*)calloc(p_st_fd->max_count+3, sizeof(int));
        if (p_fd == NULL)
        {
            printf("calloc memory error\n");
            return -1;
        }
        memcpy(p_fd, p_st_fd->fd, sizeof(int)*p_st_fd->count);
        free(p_st_fd->fd);
        p_st_fd->fd = p_fd;
        p_st_fd->max_count += 3;
    }

    p_st_fd->fd[p_st_fd->count++] = fd;
    printf("fd=%d, count===%d, max_count===%d\n", fd, p_st_fd->count, p_st_fd->max_count);

    return 0;
}

int get_max_fd(st_fd_def* p_st_fd, fd_set* p_fs)
{
    int i = 0;
    int max_fd = 0;
    max_fd = p_st_fd->fd[0];
    /*
     *   遍历fd数组,将各元素添加到描述符集中
     *   并返回数组中最大描述符
    */
    for(i = 0; i<p_st_fd->count; i++)
    {
        FD_SET(p_st_fd->fd[i], p_fs);
        if (p_st_fd->fd[i] > max_fd)
        {
            max_fd = p_st_fd->fd[i];
        }
    }
    return max_fd;
}

int remove_fd(st_fd_def* p_st_fd, int fd)
{
    int i = 0;
    int j = 0;
    /*
        删除fd数组中对应元素的值
    */
    for (; i<p_st_fd->count; i++)
    {  
        if (p_st_fd->fd[i] == fd)
        {
           for(j = i; j<p_st_fd->count; j++)
           {
                p_st_fd->fd[j] = p_st_fd->fd[j+1];
                if (j == p_st_fd->count-1)
                {
                    p_st_fd->fd[j] = -1;
                }
           }
        }
    }
    p_st_fd->count--;
    return i;
}
int destroy_fd(st_fd_def* p_st_fd)
{
    if (p_st_fd->fd != NULL)
    {
        free(p_st_fd->fd);
        free(p_st_fd-;
    }
    return 0;
}
void* thread_fun(void* arg)
{
    int max_fd = 0;
    int index = 0;
    struct timeval tv;
    char szBuff[1024];
    int read_len = 0;
    int res = 0;
    fd_set fs;
    
    //先动态申请一个结构体大小空间
    st_fd_def *p_st_fd = (st_fd_def*)arg;

    if (p_st_fd == NULL)
    {
        printf("calloc memory error, %s,%d\n", __FUNCTION__, __LINE__);
        return (void*)0;
    }
    //申请3个fd数组个数
    p_st_fd->fd = (int*)calloc(3, sizeof(int));
    if (p_st_fd->fd == NULL)
    {
        printf("calloc memory error, %s,%d\n", __FUNCTION__, __LINE__);
        return (void*)0;
    }
    p_st_fd->count = 0;
    p_st_fd->max_count =3;
    
    max_fd = get_max_fd(p_st_fd, &fs);
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    FD_ZERO(&fs);

    while(res = select(max_fd+1, &fs, NULL, NULL, &tv) >=0)
    {
        //大于0,说明有多少个读文件描述符状态发送了变化
        if (res > 0)
        {
            //遍历文件描述符数组,根据FD_ISSET查看哪些描述符状态发生了变化
            for (index = 0; index<p_st_fd->count; index++)
            {
                if (FD_ISSET(p_st_fd->fd[index], &fs))
                {
                    printf("max_fd=========%d\n", max_fd);
                    memset(szBuff, 0x00, sizeof(szBuff));
                    read_len = read(p_st_fd->fd[index], szBuff, sizeof(szBuff));
                    if (read_len <= 0)
                    {
                        printf("read socket[%d] closed\n", p_st_fd->fd[index]);
                        //当读取错误或客户端断开时,从描述符集中删除指定描述符
                        FD_CLR(p_st_fd->fd[index], &fs);
                        close(p_st_fd->fd[index]);
                        //删除描述符数组中的指定描述符
                        remove_fd(p_st_fd, p_st_fd->fd[index]);
                        continue;
                    }
                    printf("server read socket[%d] data is [%s]\n", p_st_fd->fd[index], szBuff);
                    write(p_st_fd->fd[index], szBuff, strlen(szBuff));
                }
            }
        }
        //由于服务端不断在接收新的连接,所以需要重复获取最大描述符
        max_fd = get_max_fd(p_st_fd, &fs);
    }
}


int main(int argc, char* argv[])
{
    int client_fd;
    
    int server_fd;
    int res = 0;
    int opt = 1;
    socklen_t clientaddr_len;
    struct sockaddr_in serveraddr;
    struct sockaddr_in clientaddr;
    st_fd_def  st;
    pthread_t tid;
    
    if (argc < 2)
    {
        printf("usgae: %s port\n", argv[0]);
        return -1;
    }
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0)
    {
        perror("socket error");
        return -1;
    }
    /* 端口重复利用 */
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[1]));
    serveraddr.sin_addr.s_addr = INADDR_ANY;
    
    res = bind(server_fd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr));
    if (res != 0)
    {
        perror("bind error");
        return -1;
    }
    res = listen(server_fd, 10);
    if (res != 0)
    {
        perror("listen error");
        return -1;
    }
    
    clientaddr_len = sizeof(struct sockaddr_in);
    /*
        线程函数中调用select,主线程用于接收客户端请求
    */
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&tid, NULL, thread_fun, (void*)&st);
    pthread_attr_destroy(&attr);
    
    while(1)
    {
        client_fd = accept(server_fd, (struct sockaddr*)&clientaddr, &clientaddr_len);
        if (client_fd < 0)
        {
            perror("client_fd error");
            return -1;
        }
        // 将接收的client_fd描述符放置到描述符数组中
        add_fd(&st, client_fd);
    }
    close(server_fd);
    return 0;
}

编译:gcc server_select.c -o server_select -lpthread
./server_select 8888
结果:
fd=4, count=1, max_count=3
fd=5, count=2, max_count=3
fd=6, count=3, max_count=3
fd=7, count=4, max_count=6
max_fd=7
server read socket[4] data is [aaa]
max_fd
=7
server read socket[5] data is [aaa]
max_fd=7
server read socket[6] data is [aaa]
max_fd
=7
server read socket[7] data is [aaa]
max_fd=7
read socket[4] closed
max_fd
=7
read socket[5] closed
max_fd=7
read socket[6] closed
max_fd
=7
read socket[7] closed

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章