Chinaunix首页 | 论坛 | 博客
  • 博客访问: 562847
  • 博文数量: 104
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1559
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-21 00:58
个人简介

锻炼精神,首先要锻炼肉体

文章分类

全部博文(104)

文章存档

2018年(1)

2016年(1)

2015年(101)

2014年(1)

我的朋友

分类: C/C++

2015-03-26 17:57:17

listen 函数是用于网络编程中的服务器端用于监听/聆听来自一个或是多个客户端的连接请求的,
由于在实际应用中服务器与客户端的关系通常是一对多的情况,所以服务器端通常都会在为一个
客户端请求提供服务的同时,又存储多个来不及服务的客户端请求,而这些来不及获得服务器响应或是提供服务的
客户端请求会被存放到服务器端的缓冲队列中。
服务器端每次完成一个客户端的请求的时候,会从缓冲队列中取出一个请求并为之提供相应的服务。

而 listen 函数便是接收客户端请求,并将请求置入请求缓冲队列中的方法。

所以,对于 listen 函数来说,必须要知道系统为服务器程序分配的缓冲区在哪里---> 通过socket 函数返回值标定
以及缓冲队列的长度是多少-----> 根据缓冲队列的长度来在套接字描述符指定的内存空间中为其缓冲队列分配空间。

从上面的设定便可以得知: 系统会根据自身配置来为套机字描述符分配一块默认大小的空间,缓冲队列的空间是从
这块系统默认大小的空间中进行划分的 ;如果你设定的缓冲队列长度过大,导致队列长度大于系统分配的默认缓冲区
大小的长度,便会导致错误。

listen 函数的功能仅仅用来监听请求,和通过缓冲队列来组织一下服务器来不及响应的请求,
而并非接收请求,接收请求是 accept 函数来执行的。

二者的区别便是
服务器上有这么一段 程序代码 int add( int a , int b ) ;
客户端发来请求,请求调用服务器代码来执行该段代码,来计算 a = 999 b=1 的时候的结果,
服务器通过 listen 函数监听到来自客户端的请求,便把请求记录,此时服务器端的代码还是代码;

一旦服务器决定 accept 这个请求了,那么系统便会将该程序代码加载到内存中,为代码中声明的变量
还有一些内部函数进行初始化,为其分配内存空间,以及存储返回值的空间。

就像是程序和程序源文件的区别一样。

listen 函数描述如下:
#include
int listen ( int s, int backlog ) ;

在程序中默认的函数调用顺序便是 bind ->listen

bind 是将服务器进程端口号与套接字描述符进行绑定,
listen 是通过套接字描述符来找到与该套接字描述符绑定的服务器进程,
监听各个客户端发往该服务器进程的连接请求的

参数:
 1. s 这个参数便是刚刚执行过于指定主机上的端口进行绑定的套接字描述符
 2. backlog 这个参数是用来指定服务器端最多可以接收多少个连接请求,也就是缓冲区中的
    缓冲队列的最大长度,一旦数值超过最大长度,服务器端便会拒绝接收连接请求。

实例代码:

点击(此处)折叠或打开

  1. #include <stdio.h> // perror
  2. #include <string.h> // memset

  3. #include <unistd.h> // close
  4. #include <netinet/in.h> // struct sockaddr_in
  5. #include <sys/types.h> // AF_INET , SOCK_STREAM
  6. #include <sys/socket.h> // socket , bind , listen


  7. #define MAX_QUEUE_LENGTH 10

  8. int getSocketDone ( )
  9. {
  10.    return socket( AF_INET, SOCK_STREAM, 0 ) ;
  11. }

  12. int getBindDone ( int sock_fd )
  13. {
  14.   struct sockaddr_in serv_addr ;
  15.  
  16.   // initialize the sockaddr_in
  17.   memset ( &serv_addr , 0 , sizeof ( struct sockaddr_in )) ;
  18.   serv_addr.sin_family = AF_INET ;
  19.   serv_addr.sin_port = htons (3699) ;
  20.   serv_addr.sin_addr.s_addr = htonl (INADDR_ANY) ;
  21.   // finish initializing
  22.  
  23.   return bind ( sock_fd , (struct sockaddr *)(&serv_addr) , sizeof(struct sockaddr_in) ) ;
  24.  
  25. }


  26. int getListenDone ( int sock_fd )
  27. {
  28.   return listen( sock_fd , MAX_QUEUE_LENGTH ) ;
  29. }


  30. int main ( int c , char **v )
  31. {
  32.   int ret , sock_fd ;

  33.   sock_fd = getSocketDone () ;
  34.   
  35.   if ( sock_fd > 0 )
  36.   {
  37.     printf ("success calling getSocketDone \n") ;
  38.   
  39.     ret = getBindDone ( sock_fd ) ;
  40.     
  41.     if ( !ret )
  42.     {
  43.        printf ("success calling getBindDone \n") ;
  44.         
  45.        ret = getListenDone ( sock_fd ) ;
  46.         
  47.        if (! ret )
  48.        {
  49.            printf(" success calling getListenDone \n") ;
  50.        }
  51.     
  52.        else
  53.        {
  54.            perror (" failed call getListenDone") ;
  55.            return -1 ;
  56.         }
  57.    }
  58.    else
  59.    {
  60.       perror ("failed call getBindDone") ;
  61.       return -1 ;
  62.    }

  63.  }
  64. else
  65. {
  66.    perror ("failed call getSocketDone") ;
  67.    return -1 ;
  68. }


  69.  return 0 ;
  70. }
运行结果:

success calling getSocketDone 
success calling getBindDone 
 success calling getListenDone 
阅读(2526) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~