Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->系统管理 ->正文

Linux操作系统中BSD套接口开发的基础介绍

来源:Linux-cn.com 作者:Webmaster 时间:2007-05-05 点击: [收藏] [投稿]

   */

  /*
   * SO_REUSEADDR选项的设置将套接口设置成重新使用旧的地址(IP地址加端口号)而不等待
   * 注意:在Linux系统中,如果一个socket绑定了某个端口,该socket正常关闭或程序退出后,
   * 在一段时间内该端口依然保持被绑定的状态,其他程序(或者重新启动  的原程序)无法绑定该端口。
   *
   * 下面的调用中:SOL_SOCKET代表对SOCKET层进行操作
   */
  on = 1;

  status = setsockopt(serverSocket, SOL_SOCKET,
  SO_REUSEADDR,
    (const char *) &on, sizeof(on));

  if (-1 == status)
  {
    perror("setsockopt(...,SO_REUSEADDR,...)");
  }

  /* 当连接中断时,需要延迟关闭(linger)以保证所有数据都
   * 被传输,所以需要打开SO_LINGER这个选项
   * linger的结构在/usr/include/linux/socket.h中定义:
   *  struct linger
   *  {
   *   int l_onoff;  /* Linger active */
   *   int l_linger;  /* How long to linger */
   *  };

   *  如果l_onoff为0,则延迟关闭特性就被取消。如果非零,则允许套接口延迟关闭。
   *  l_linger字段则指明延迟关闭的时间
   */

  {
    struct linger linger = { 0 };

    linger.l_onoff = 1;
    linger.l_linger = 30;
    status = setsockopt(serverSocket,
  SOL_SOCKET, SO_LINGER,
  (const char *) &linger,
  sizeof(linger));

    if (-1 == status)
    {
      perror("setsockopt(...,SO_LINGER,...)");
    }
  }

  /*
   * find out who I am
   */

  status = gethostname(hostname,
  sizeof(hostname));
  if (-1 == status)
  {
    perror("gethostname()");
    exit(1);
  }

  hostPtr = gethostbyname(hostname);
  if (NULL == hostPtr)
  {
    perror("gethostbyname()");
    exit(1);
  }

  (void) memset(&serverName, 0,
  sizeof(serverName));
  (void) memcpy(&serverName.sin_addr,
  hostPtr->h_addr,
  hostPtr->h_length);
   /*
    *h_addr是h_addr_list[0]的同义词,
    *  h_addr_list是一组地址的数组
    *长度为4(byte)代表一个IP地址的长度
    */
/*
 * 为了使服务器绑定本机所有的IP地址,
 * 上面一行代码需要用下面的代码代替
 * serverName.sin_addr.s_addr=htonl(INADDR_ANY);
 */

  serverName.sin_family = AF_INET;
  /* htons:h(host byteorder,主机字节序)
   *     to n(network byteorder,网络字节序
   *     s(short类型)
   */
  serverName.sin_port = htons(port);
/* 在一个地址(本例中的serverSocket)被建立后
 * 它就应该被绑定到我们获得的套接口。
 */
  status = bind(serverSocket,
 (struct sockaddr *) &serverName,
    sizeof(serverName));
  if (-1 == status)
  {
    perror("bind()");
    exit(1);
  }
/* 现在套接口就可以被用来监听新的连接。
 * BACK_LOG指定了未决连接监听队列(listen queue for pending connections)
 * 的最大长度。当一个新的连接到达,而队列已满的话,客户就会得到连接拒绝错误。

 * (这就是dos拒绝服务攻击的基础)。
 */
  status = listen(serverSocket, BACK_LOG);
  if (-1 == status)
  {
    perror("listen()");
    exit(1);
  }
/* 从这里开始,套接口就开始准备接受请求,并为他们服务。
 * 本例子是用for循环来达到这个目的。一旦连接被接受(accpepted),
 * 服务器可以通过指针获得客户的地址以便进行一些诸如记录客户登陆之类的
 * 任务。
  for (;;)
  {
    struct sockaddr_in clientName = { 0 };
    int slaveSocket, clientLength =
  sizeof(clientName);

    (void) memset(&clientName, 0,
  sizeof(clientName));

    slaveSocket = accept(serverSocket,
  (struct sockaddr *) &clientName,
  &clientLength);
    if (-1 == slaveSocket)
    {
      perror("accept()");
      exit(1);
    }

    childPid = fork();

    switch (childPid)
    {
    case -1: /* ERROR */
      perror("fork()");
      exit(1);

    case 0: /* child process */

      close(serverSocket);

      if (-1 == getpeername(slaveSocket,
  (struct sockaddr *) &clientName,
  &clientLength))
      {
        perror("getpeername()");
      }
      else
      {
      printf("Connection request from %s\n",
          inet_ntoa(clientName.sin_addr));
      }

      /*
       * Server application specific code
       * goes here, e.g. perform some
       * action, respond to client etc.
       */
      write(slaveSocket, MESSAGE,
  strlen(MESSAGE));
        /* 也可以使用带缓存的ANSI函数fprint,
        * 只要你记得必要时用fflush刷新缓存
        */
      close(slaveSocket);

 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:享受便利的应用方式—Linux系统三则超酷技巧   下一篇:浅析Linux操作系统登录帐户的管理和审计

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章
Power by linux-cn.com 粤ICP备05006655号