阅读更多
判断socket是否阻塞式:
// sock option O_NONBLOCK
// return -1 if error, and errno is set appropriately. otherwise return O_NONBLOCK option
// which if non-block flag is not set, return 0, and if non-block flag is set, return O_NONBLOCK.
//
// also ORing SOCK_NONBLOCK flag when create socket:
// socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
int getsocknonblockopt(int fd)
{
int fd_flags = fcntl(fd, F_GETFL);
return fd_flags == -1 ? -1 : fd_flags & O_NONBLOCK;
}
在调用accept系统调用函数时,出现14号errno错误,查看定义如下:
#defineEFAULT 14/* Bad address */
在https://linux.die.net/man/2/accept4上对该错误描述如下:
EFAULT The addr argument is not in a writable part of the user address space.
这个错误很少遇到,无意中把代码写成:
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
void handle_accept(int fd)
{
handle_connect(fd);
handle_accept(fd);
}
handle_accept内部递归调用,导致出现上面那个错误。
将accept这段代码注释掉后,
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
/*
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
*/
}
程序启动后进程就直接退出,没报任何错误,唯一确定是已经出错的原因是因为产生了.stackdump文件,但该文件是空的。也无法根据.stackdump文件去定位原因。
阻塞式(Blocking):
#include
#include
#include
#include
#include
#include
#include
#include
#include
// posix thread
#include
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
int start_routine_arg(void *arg)
{
return *((int*) arg);
}
void handle_accept(int fd)
{
handle_connect(fd);
handle_accept(fd);
}
void* accept_handler(void *arg)
{
pthread_t tid = pthread_self();
int fd = start_routine_arg(arg);
handle_accept(fd);
printf("tid %d\n", tid);
printf("fd %d\n", fd);
int *result = (int *) malloc(sizeof(int));
*result = 9;
return (void *) result;
}
// $ objdump -D -S server.exe > server.rasm
int main()
{
int fd;
struct sockaddr_in sock_addr;
pthread_t pt;
int result = 0;
int *presult = &result;
int **ppresult = &presult;
printf("%d\n", **ppresult);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
printf("socket error %d\n", errno);
return -1;
}
printf("fd %d\n", fd);
bzero(&sock_addr, sizeof(struct sockaddr_in));
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
sock_addr.sin_port = htons(2121);
if(bind(fd, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error %d\n", errno);
return -1;
}
if (listen(fd, 50) == -1)
{
printf("listen error %d\n", errno);
return -1;
}
if (pthread_create(&pt, NULL, accept_handler, (void *) &fd))
{
return -1;
}
if (pthread_join(pt, (void **) ppresult))
{
return -1;
}
printf("%d\n", **ppresult);
printf("...\n");
return 0;
}
非阻塞式(Non-Blocking):
可以通过fcntl函数设置O_NONBLOCK使socket工作在非阻塞式(Non-Blocking)模式下。
从Linux 2.6.27后,还可以在创建socket的时候设置SOCK_NONBLOCK使socket工作在非阻塞式(Non-Blocking)模式下,这种方式是Linux-specific的。
以下非阻塞式(Non-Blocking)例子是在创建socket的时候设置SOCK_NONBLOCK使socket工作在非阻塞式(Non-Blocking)模式
#include
#include
#include
#include
#include
#include
#include
#include
#include
// posix thread
#include
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT 1236
typedef struct Args
{
char *host;
int port;
int backlog;
} Args_t;
Args_t* parseArgs(int argc, char** argv, Args_t* args)
{
// mask param host setting(0x01), and param port setting(0x02)
unsigned short mask = 0;
if (argc > 1)
{
char** p_argv = argv;
int i;
for (i = 1; i < argc; i++)
{
char *s_param = *(p_argv + i);
if (! strcmp("-h", s_param) || ! strcmp("--help", s_param) || ! strcmp("/?", s_param))
{
__USAGES:
printf("%s\n", *argv);
printf("options:\n");
printf("\t-h --help /?\n");
printf("\t usage.\n");
printf("\t-H --host[=localhost]\n");
printf("\t the host to bind, default to localhost. well-form with formats: \n");
printf("\t 1) -Hhost, for example: -Hlocalhost\n");
printf("\t 2) --host=host, for example: --host=localhost\n");
printf("\t 3) --host host, for example: --host localhost\n");
printf("\t if any, for example -Hany Or --host=any Or --host any, this represents INADDR_ANY while binding.\n");
printf("\t--bind-any\n");
printf("\t represents INADDR_ANY while binding. this same as -Hany Or --host=any Or --host any\n");
printf("\t-p --port[=1236]\n");
printf("\t the port to listen, default to 1236. well-form with formats: \n");
printf("\t 1) -pport, for example: -p1236\n");
printf("\t 2) --port=port, for example: --port=1236\n");
printf("\t 3) --port port, for example: --port 1236\n");
printf("\t--backlog[=50]\n");
printf("\t represents the maximum length to which the queue of pending connections.\n");
return NULL;
}
else if (! strncmp("-H", s_param, 2))
{
char *host;
if (mask & 0x01)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
host = s_param + 2;
args->host = host;
mask |= 0x01;
}
else if (! strncmp("--host", s_param, 6))
{
if (mask & 0x01)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--host", s_param))
{
if (i + 1 < argc)
{
args->host = *(p_argv + (++i));
}
else
{
printf("invalid param: %s, well-form with formats: --host=host Or --host host\n", s_param);
goto __USAGES;
}
}
else if(! strncmp("--host=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
args->host = token;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x01;
}
else if (! strcmp("--bind-any", s_param))
{
args->host = "any";
}
else if (! strncmp("-p", s_param, 2))
{
int port;
if (mask & 0x02)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
port = atoi(s_param + 2);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x02;
}
else if (! strncmp("--port", s_param, 6))
{
if (mask & 0x02)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--port", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int port = atoi(s_param);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --port=port Or --port port\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--port=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int port = atoi(token);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x02;
}
else if (! strncmp("--backlog", s_param, 9))
{
if (mask & 0x04)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--backlog", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int backlog = atoi(s_param);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --backlog=backlog Or --backlog backlog\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--backlog=", s_param, 10))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int backlog = atoi(token);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x04;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
}
return args;
}
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
int start_routine_arg(void *arg)
{
return *((int*) arg);
}
void handle_accept(int fd)
{
handle_connect(fd);
//handle_accept(fd);
}
void* accept_handler(void *arg)
{
pthread_t tid = pthread_self();
int fd = start_routine_arg(arg);
printf("tid %d\n", tid);
printf("fd %d\n", fd);
while (1)
{
handle_accept(fd);
}
int *result = (int *) malloc(sizeof(int));
*result = 9;
return (void *) result;
}
// $ objdump -D -S server.exe > server.rasm
void main(int argc, char** argv)
{
int fd;
struct sockaddr_in sock_addr; // #include
Args_t args = {DEFAULT_HOST, DEFAULT_PORT, 50};
pthread_t pt;
int result = 0;
int *presult = &result;
int **ppresult = &presult;
printf("%d\n", **ppresult);
if (parseArgs(argc, argv, &args) == NULL)
{
return;
}
printf("listening on %s:%d, backlog: %d\n", strcmp("any", args.host) == 0 ? "" : args.host, args.port, args.backlog);
#ifndef SOCK_NONBLOCK
#error "SOCK_NONBLOCK not support."
#endif
fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd == -1)
{
printf("socket error %d\n", errno);
return;
}
printf("fd %d\n", fd);
bzero(&sock_addr, sizeof(struct sockaddr_in)); // #include
sock_addr.sin_family = AF_INET;
if (! strcmp("any", args.host))
{
printf("bind any\n");
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else if (! strcmp("localhost", args.host))
{
in_addr_t sin_addr = inet_addr("127.0.0.1");
if (sin_addr == INADDR_NONE)
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
sock_addr.sin_addr.s_addr = sin_addr;
}
else
{
if (! inet_aton(args.host, &(sock_addr.sin_addr)))
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
}
sock_addr.sin_port = htons(args.port);
if(bind(fd, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error %d\n", errno);
return;
}
if (listen(fd, args.backlog) == -1)
{
printf("listen error %d\n", errno);
return;
}
if (pthread_create(&pt, NULL, accept_handler, (void *) &fd))
{
printf("pthread create error %d\n", errno);
return;
}
if (pthread_join(pt, (void **) ppresult))
{
printf("pthread join error %d\n", errno);
return;
}
printf("%d\n", **ppresult);
}
以下
非
阻塞式(Non-Blocking)例子是
通过fcntl函数设置O_NONBLOCK使socket工作在
非
阻塞式(Non-Blocking)模式
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// posix thread
#include
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT 1236
typedef struct Args
{
char *host;
int port;
int backlog;
} Args_t;
Args_t* parseArgs(int argc, char** argv, Args_t* args)
{
if (argc > 1)
{
char** p_argv = argv;
int port_set_flag = 0, allow_port_0 = 0;
int i;
for (i = 1; i < argc; i++)
{
char *s_param = *(p_argv + i);
if (! strcmp("-h", s_param) || ! strcmp("--help", s_param) || ! strcmp("/?", s_param))
{
__USAGES:
printf("%s\n", *argv);
printf("options:\n");
printf("\t-h --help /?\n");
printf("\t usage.\n");
printf("\t-H --host[=localhost]\n");
printf("\t the host to bind, default to localhost. well-form with formats: \n");
printf("\t 1) -Hhost, for example: -Hlocalhost\n");
printf("\t 2) --host=host, for example: --host=localhost\n");
printf("\t 3) --host host, for example: --host localhost\n");
printf("\t if any, for example -Hany Or --host=any Or --host any, this represents INADDR_ANY while binding.\n");
printf("\t--bind-any\n");
printf("\t represents INADDR_ANY while binding. this same as -Hany Or --host=any Or --host any\n");
printf("\t-p --port[=1236]\n");
printf("\t the port to listen, default to 1236. well-form with formats: \n");
printf("\t 1) -pport, for example: -p1236\n");
printf("\t 2) --port=port, for example: --port=1236\n");
printf("\t 3) --port port, for example: --port 1236\n");
printf("\t the port set to 0 is not a satisfied value, a random port would be assigned. by default the port set to 0 is not allowed\n");
printf("\t--allow-port-zero\n");
printf("\t default, the port set to 0 is not allowed, param --allow-port-zero allow the port set to 0\n");
printf("\t--backlog[=50]\n");
printf("\t represents the maximum length to which the queue of pending connections.\n");
return NULL;
}
else if (! strncmp("-H", s_param, 2))
{
char *host;
if (args->host != NULL)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
host = s_param + 2;
args->host = host;
}
else if (! strncmp("--host", s_param, 6))
{
if (args->host != NULL)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--host", s_param))
{
if (i + 1 < argc)
{
args->host = *(p_argv + (++i));
}
else
{
printf("invalid param: %s, well-form with formats: --host=host Or --host host\n", s_param);
goto __USAGES;
}
}
else if(! strncmp("--host=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
args->host = token;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else if (! strcmp("--bind-any", s_param))
{
if (args->host != NULL)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
args->host = "any";
}
else if (! strncmp("-p", s_param, 2))
{
int port;
if (args->port > 0)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
port = atoi(s_param + 2);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--port", s_param, 6))
{
if (args->port > 0)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--port", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int port = atoi(s_param);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --port=port Or --port port\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--port=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int port = atoi(token);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else if (! strcmp("--allow-port-zero", s_param))
{
allow_port_0 = 1;
}
else if (! strncmp("--backlog", s_param, 9))
{
if (args->backlog > 0)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--backlog", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int backlog = atoi(s_param);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --backlog=backlog Or --backlog backlog\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--backlog=", s_param, 10))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int backlog = atoi(token);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
if (! allow_port_0 && args->port == 0)
{
fprintf(stderr, "port set to 0 is not allowed\n");
goto __USAGES;
}
}
return args;
}
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
int start_routine_arg(void *arg)
{
return *((int*) arg);
}
void handle_accept(int fd)
{
handle_connect(fd);
//handle_accept(fd);
}
void* accept_handler(void *arg)
{
pthread_t tid = pthread_self();
int fd = start_routine_arg(arg);
printf("tid %d\n", tid);
printf("fd %d\n", fd);
while (1)
{
handle_accept(fd);
}
int *result = (int *) malloc(sizeof(int));
*result = 9;
return (void *) result;
}
// $ objdump -D -S server.exe > server.rasm
void main(int argc, char** argv)
{
int fd, fd_flags;
struct sockaddr_in sock_addr; // #include
Args_t args;
memset(&args, 0, sizeof(Args_t));
pthread_t pt;
int result = 0;
int *presult = &result;
int **ppresult = &presult;
printf("%d\n", **ppresult);
if (parseArgs(argc, argv, &args) == NULL)
{
return;
}
if (args.host == NULL)
{
args.host = DEFAULT_HOST;
}
if (args.port == 0)
{
args.port = DEFAULT_PORT;
}
if (args.backlog == 0)
{
args.backlog = 50;
}
printf("listening on %s:%d, backlog: %d\n", strcmp("any", args.host) == 0 ? "" : args.host, args.port, args.backlog);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
printf("socket error %d\n", errno);
return;
}
printf("fd %d\n", fd);
fd_flags = fcntl(fd, F_GETFL);
if (fd_flags == -1)
{
fprintf(stderr, "fcntl error %d\n", errno);
return;
}
fd_flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, fd_flags) == -1)
{
fprintf(stderr, "fcntl error %d\n", errno);
return;
}
bzero(&sock_addr, sizeof(struct sockaddr_in)); // #include
sock_addr.sin_family = AF_INET;
if (! strcmp("any", args.host))
{
printf("bind any\n");
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else if (! strcmp("localhost", args.host))
{
in_addr_t sin_addr = inet_addr("127.0.0.1");
if (sin_addr == INADDR_NONE)
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
sock_addr.sin_addr.s_addr = sin_addr;
}
else
{
if (! inet_aton(args.host, &(sock_addr.sin_addr)))
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
}
sock_addr.sin_port = htons(args.port);
if(bind(fd, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error %d\n", errno);
return;
}
if (listen(fd, args.backlog) == -1)
{
printf("listen error %d\n", errno);
return;
}
if (pthread_create(&pt, NULL, accept_handler, (void *) &fd))
{
printf("pthread create error %d\n", errno);
return;
}
if (pthread_join(pt, (void **) ppresult))
{
printf("pthread join error %d\n", errno);
return;
}
printf("%d\n", **ppresult);
}
非阻塞式(Non-Blocking) + select模型:
/*
* $ gcc -c selecttest.c -o selecttest.o
* $ gcc selecttest.o -o selecttest
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 16191
#define MAX_CONNECTION_NUM 1024
int socket_setnonblock(int fd)
{
int flags = fcntl(fd, F_GETFL);
if (flags == -1)
{
printf("fcntl error %d\n", errno);
return -1;
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1)
{
printf("fcntl error %d\n", errno);
return -1;
}
return 0;
}
int _socket(int domain, int type, int protocol)
{
return socket(domain, type, protocol);
}
int socket_bind(int sock, unsigned short int port)
{
printf("bind to port %d\n", port);
struct sockaddr_in sock_addr;
bzero(&sock_addr, sizeof(struct sockaddr_in));
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
sock_addr.sin_port = htons(port);
if(bind(sock, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error %d\n", errno);
return -1;
}
return 0;
}
int socket_listen(int sock)
{
if (listen(sock, 50) == -1)
{
printf("listen error %d\n", errno);
return -1;
}
return 0;
}
int max_fd(int fd, int *fdset, int fd_size)
{
int max = fd;
if (fdset != NULL)
{
int i;
for (i = 0; i < fd_size; i++)
{
if (fdset[i] != 0)
{
if (fdset[i] > max)
{
max = fdset[i];
}
}
}
}
return max;
}
void add_selecting_list(int fd, int* fdset, int* fd_size)
{
int i;
for (i = 0; i < MAX_CONNECTION_NUM; i++)
{
if (fdset[i] == 0)
{
fdset[i] = fd;
(*fd_size)++;
break;
}
}
}
int main(int argc, char** argv)
{
char* var_port = NULL;
int port;
int fd = -1;
int nfds = MAX_CONNECTION_NUM + 1;
struct fd_set fds;
struct timeval timeout = {3/* tv_sec: seconds */, 0 /* tv_usec: microseconds */};
int selected = -1;
int fd_size = 0;
int *fdset = NULL;
var_port = getenv("port");
if (var_port == NULL) {
char *new_var_port = NULL;
printf("env variable=port not exists, set env variable port=%d\n", PORT);
if (setenv("port", "16191", 0) != 0)
{
printf("set env variable error: %d\n", errno);
return 1;
}
printf("set env variable ok\n");
new_var_port = getenv("port");
printf("env variable=port: %s\n", new_var_port);
port = PORT;
}
else
{
port = atoi(var_port);
}
printf("port: %d\n", port);
#ifdef USE_SOCK_NONBLOCK
fd = _socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
#else
fd = _socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
printf("socket error %d\n", errno);
return 1;
}
else
{
printf("socket ok, socket: %d\n", fd);
}
socket_setnonblock(fd);
#endif
if (socket_bind(fd, port) == -1)
{
return -1;
}
if (socket_listen(fd) == -1)
{
return -1;
}
fdset = (int *) malloc(MAX_CONNECTION_NUM * sizeof(int));
nfds = max_fd(fd, fdset, MAX_CONNECTION_NUM) + 1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
while (1)
{
int i;
printf("selecting...%d\n", fd_size + 1);
printf("%d(server)\t", fd);
for (i = 0; i < fd_size; i++)
{
printf("%d\t", fdset[i]);
}
printf("\n");
nfds = max_fd(fd, fdset, MAX_CONNECTION_NUM) + 1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
for (i = 0; i < fd_size; i++)
{
if (fdset[i] != 0)
{
FD_SET(fdset[i], &fds);
}
}
selected = select(nfds, &fds, &fds, &fds, &timeout);
if (selected == -1)
{
printf("select error: %d\n", errno);
}
else if (selected == 0)
{
printf("no selected...continue...\n");
}
else
{
printf("selected %d\n", selected);
if (FD_ISSET(fd, &fds))
{
int new_fd = -1;
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
new_fd = accept(fd, &sock_addr, &addrlen);
if (new_fd == -1)
{
if (errno == EWOULDBLOCK)
{
}
else
{
printf("accept error %d\n", errno);
}
continue;
}
else
{
printf("accept new connection from %d\n", new_fd);
if (fd_size >= MAX_CONNECTION_NUM)
{
printf("refuse new connection from %d, max connection limit: %d\n", new_fd, MAX_CONNECTION_NUM);
}
else
{
add_selecting_list(new_fd, fdset, &fd_size);
}
}
}
for (i = 0; i < MAX_CONNECTION_NUM; i++)
{
if (fdset[i] != 0)
{
if (FD_ISSET(fdset[i], &fds))
{
char buf[1024] = {0};
ssize_t nbytes = read(fdset[i], buf, 1024);
if (nbytes == -1)
{
if (errno == ECONNRESET)
{
printf("connection from %d reset by peer, remove from selecting list\n", fdset[i]);
fdset[i] = 0;
fd_size--;
}
else if (errno == EWOULDBLOCK)
{
continue;
}
else
{
printf("read error %d\n", errno);
}
}
else
{
printf("read data(%dbytes):%s\n", nbytes, buf);
}
}
}
}
}
}
}