网络编程
BIO
BIO即阻塞式IO
NIO
NIO即非阻塞式IO
Socket NIO需要将socket设置为非阻塞式socket。
AIO
AIO即异步IO
select
poll
epoll
在调用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<stdio.h> #include <stdlib.h> #include <string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> // posix thread #include <pthread.h> 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> // posix thread #include <pthread.h> #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 <netinet/in.h> 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 <string.h> 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> // posix thread #include <pthread.h> #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 <netinet/in.h> 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 <string.h> 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <sys/time.h> #include <sys/select.h> #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); } } } } } } }