linux select I/O共享服务端

花了两天时间,终于写好了一个select I/O复用服务端,真不容易,拿出来和大伙分享一下,O(∩_∩)O~


/******************************************************************************

  Copyright (C), 2001-2011, DCN Co., Ltd.

 ******************************************************************************
  File Name     : main.c
  Version       : Initial Draft
  Author        : Dong Shen
  Created       : 2012/9/19
  Last Modified :
  Description   : transcode main
******************************************************************************/


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


#include <m_type.h>

#define MYPORT          1234    // the port users will be connecting to
#define BACKLOG         512     // how many pending connections queue will hold
#define BUF_SIZE        1024

#define MAX_PATH_LEN    255

#ifndef bool
    #define bool int
#endif

#define FALSE 0
#define TRUE  1

typedef enum media_handle_e
{
    E_NONE      = 0,
    E_PARSER    = 1,
    E_TRANSCODE = 2
}media_handle_e;

typedef enum platform_e
{
    E_PF_NONE   = 0,
    E_PF_PC     = 1,
    E_PF_PAD    = 2,
    E_PF_PHONE  = 3
}platform_e;

typedef struct fd_a_t
{
    int     fd_a;    
    bool    need_write;

    media_handle_e handle_type;

    char path[MAX_PATH_LEN];
    char out_path[MAX_PATH_LEN];
    SO_Format_Type fmt_type;
    SO_Codec_ID v_codec;
    SO_Codec_ID a_codec;
    int * bitrate;
    int bitrate_count;
    int width;
    int height;
    char * plat_form;
    
    char *  ret_buf;
    int     ret_buf_len;
    TAILQ_ENTRY(fd_a_t) fd_a_node;
}fd_a_t;

typedef  TAILQ_HEAD(fd_a_list_t_, fd_a_t) fd_a_list_t;

int main(void)
{    
    int ret     = 0;
    int sock_fd = 0; // listen on sock_fd
    int new_fd  = 0; // new connection on new_fd
    struct sockaddr_in server_addr; // server address information
    struct sockaddr_in client_addr; // connector's address information
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    memset(&client_addr, 0, sizeof(struct sockaddr_in));
    

    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sock_fd) 
    {
        perror("socket");
        return -1;
    }
  
    int yes = 1;  
    ret = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));  
    if (-1 == ret)   
    {  
        perror("setsockopt");  
        return -1;  
    }  

    server_addr.sin_family      = AF_INET;              // host byte order
    server_addr.sin_port        = htons(MYPORT);        // short, network byte order
    server_addr.sin_addr.s_addr = INADDR_ANY;           // automatically fill with my IP
    memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));

    ret = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (-1 == ret) 
    {
        perror("bind");
        return -1;
    }

    ret = listen(sock_fd, BACKLOG);
    if (-1 == ret)
    {
        perror("listen");
        return -1;
    }


    int maxsock     = 0;
    int conn_amount = 0;
    fd_a_list_t  fd_a_hd;
    TAILQ_INIT(&fd_a_hd);
    
    fd_set read_fdsr;
    fd_set write_fdsr;
         
    // timeout setting    
    // struct timeval tv;    
        
    while (1) 
    {
        // tv.tv_sec = 30;
        // tv.tv_usec = 0;
        
        // initialize file descriptor set    
        FD_ZERO(&read_fdsr);
        FD_ZERO(&write_fdsr);
        FD_SET(sock_fd, &read_fdsr);
        // FD_SET(sock_fd, &write_fdsr);
        maxsock = sock_fd;

        fd_a_t * cur_fd_node = TAILQ_FIRST(&fd_a_hd);
        while (cur_fd_node != NULL)
        {
            FD_SET(cur_fd_node->fd_a, &read_fdsr);
            FD_SET(cur_fd_node->fd_a, &write_fdsr);
            if (cur_fd_node->fd_a > maxsock)
            {
                maxsock = cur_fd_node->fd_a;
            }
            cur_fd_node = TAILQ_NEXT(cur_fd_node, fd_a_node);
            
        }

        // select read write socket fd, read_fdsr.
        ret = select(maxsock + 1, &read_fdsr, &write_fdsr, NULL, NULL);
        if (ret < 0) 
        {
            perror("select");
            break;
        } 
        else if (ret == 0) 
        {
            printf("select timeout\n");
            continue;
        }
        
        // check whether a new connection comes
        if (FD_ISSET(sock_fd, &read_fdsr)) 
        {
            int sin_size = sizeof(client_addr);
            new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
            if (new_fd <= 0) 
            {
                perror("accept");
                continue;
            }

            // add to fd queue
            if (conn_amount < BACKLOG) 
            {
                // create new fd node, insert into fd list
                fd_a_t * new_fd_a_node  = calloc(1, sizeof(fd_a_t));
                new_fd_a_node->fd_a     = new_fd;
                TAILQ_INSERT_TAIL(&fd_a_hd, new_fd_a_node, fd_a_node);
                conn_amount++;
                
                printf("new connection client[%d] %s:%d\n", new_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));        
            }
            else 
            {
                printf("max connections arrive, exit\n");
                send(new_fd, "bye", 4, 0);
                close(new_fd);
                continue;
            }
        }

        // check every fd in the set
        cur_fd_node = TAILQ_FIRST(&fd_a_hd);
        while(cur_fd_node != NULL)
        {
            if (FD_ISSET(cur_fd_node->fd_a, &read_fdsr))
            {
                char recv_buf[BUF_SIZE] = {0};
                int ret_len = recv(cur_fd_node->fd_a, recv_buf, sizeof(recv_buf), 0);
                if (ret_len <= 0) // client close
                {        
                    printf("client[%d] close\n", cur_fd_node->fd_a);
                          
                    // close socket, clear fd_set
                    close(cur_fd_node->fd_a);
                    
                    // remove fd_node from fd_list
                    fd_a_t * next_fd_node = TAILQ_NEXT(cur_fd_node, fd_a_node);
                    TAILQ_REMOVE(&fd_a_hd, cur_fd_node, fd_a_node);

                    free_node(cur_fd_node);
                    
                    cur_fd_node = next_fd_node;
                    conn_amount--;

                    continue;
                } 
                else // receive data
                {        
                    printf("revice client[%d] msg:%s\n", cur_fd_node->fd_a, recv_buf);

                    str_parser(recv_buf, ret_len, cur_fd_node);

                    if (E_PARSER == cur_fd_node->handle_type)
                    {
                        media_parser(cur_fd_node);
                    }
                    else if (E_TRANSCODE == cur_fd_node->handle_type)
                    {
                        media_transcode(cur_fd_node);
                    }
                    else
                    {
                        ;
                    }

                    cur_fd_node->need_write = TRUE;
                                        
                }
            }

            if (FD_ISSET(cur_fd_node->fd_a, &write_fdsr))
            {
                if (TRUE == cur_fd_node->need_write)
                {            
                    printf("server send msg %s, len %d\n", cur_fd_node->ret_buf, cur_fd_node->ret_buf_len);

                    send(cur_fd_node->fd_a, cur_fd_node->ret_buf, cur_fd_node->ret_buf_len, 0);
                    cur_fd_node->need_write = FALSE;
                }
            }

            cur_fd_node = TAILQ_NEXT(cur_fd_node, fd_a_node);
        }   
    }

    fd_a_t * cur_fd_node = NULL;
    while ((cur_fd_node = TAILQ_FIRST(&fd_a_hd)) != NULL)
    {
        printf("client[%d] close\n", cur_fd_node->fd_a);
        
        // close socket, clear fd_set
        close(cur_fd_node->fd_a);
        
        // remove fd_node from fd_list
        TAILQ_REMOVE(&fd_a_hd, cur_fd_node, fd_a_node);

        free_node(cur_fd_node);
        
        conn_amount--;        
    }
    
    return 1;
}


 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值