Linux C服务器网络编程:阻塞式、非阻塞式、select模型

阅读更多

判断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);
                        }
                    }
                }
            }
        }
    }
}

 

你可能感兴趣的:(Linux C服务器网络编程:阻塞式、非阻塞式、select模型)