花了两天时间,终于写好了一个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;
}