Linux/Unix网络编程指南(Socket 编程)—(10)
作者:转载自:更新时间:2009-8-2

close() 和 shutdown()--Get outta my face!
你已经整天都在发送 (send()) 和接收 (recv()) 数据了,现在你准备 关闭你的套接口描述符了。这很简单,你可以使用一般的 Unix 文件描述符的 close() 函 数:
  close(sockfd);
他将防止套接口上更多的数据的读写。任何在另一端读写套接口的企图都将返回错误信息。
如果你想在如何关闭套接口上有多一点的控制,你可以使用函数 shutdown()。他能够让 你将一定方向的通讯或者双向的通讯(就象 close() 一样)关闭,你可以使用:
  int shutdown(int sockfd, int how);
sockfd 是你想要关闭的套接口文件描述复。how 的值是下面的其中之一:
0 - Further receives are disallowed
1 - Further sends are disallowed
2 - Further sends and receives are disallowed (和 close() 一样
shutdown() 成功时返回 0,失败时返回 -1(同时设置 errno。)
如果在无连接的数据报套接口中使用 shutdown(),那么只不过是让 send() 和 recv() 不能使用(记得你在数据报套接口中使用了 connect 后是可以 使用他们的吗?)
--------------------------------------------------------------------------------
getpeername()--Who are you?
这个函数太简单了。
他太简单了,以至我都不想单列一章。但是我还是这样做了。
函数 getpeername() 告诉你在连接的流式套接口上谁在另外一边。函数是这样的:
  #include <sys/socket.h>
  int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
sockfd 是连接的流式套接口的描述符。addr 是一个指向结构 struct sockaddr (或者是 struct sockaddr_in) 的指针,他保存着 连接的另一边的信息。addrlen 是一个 int 型的指针,他初始化为 sizeof(struct sockaddr)。
函数在错误的时候返回 -1,设置相应的 errno。
一旦你获得他们的地址,你可以使用 inet_ntoa() 或者 gethostbyaddr() 来打印或者获得更多的信息。但是你不能得到他的帐号。(如果他运行着愚蠢的守护进程,这是 可能的,但是他的讨论已经超出了本文的范围,请参考 RFC-1413 以获得更多的信息。)
-------------------------------------------------------------------------------
gethostname()--Who am I?
甚至比 getpeername() 还简单的函数是 gethostname()。他返回你程序 所运行的机器的主机名字。然后你可以使用 gethostbyname() 以获得你的机器的 IP 地址。
下面是定义:
  #include <unistd.h>
  int gethostname(char *hostname, size_t size);
参数很简单:hostname 是一个字符数组指针,他将在函数返回时保存 主机名。size 是 hostname 数组的字节长度。
函数调用成功时返回 0,失败时返回 -1,并设置 errno。
--------------------------------------------------------------------------------
DNS--You say "whitehouse.gov", I say "198.137.240.100"
如果你不知道 DNS 的意思,那么我告诉你,他代表"域名服务 (Domain Name Service)"。他主要的功能是:你给他一个容易记忆的某站点的地址,他给你 IP 地址(然后你就可以 使用 bind(), connect(), sendto() 或者其他函数。)当一个人 输入:
  $ telnet whitehouse.gov
telnet 能知道他将连接 (connect()) 到 "198.137.240.100"。
但是这是如何工作的呢? 你可以调用函数 gethostbyname():
  #include <netdb.h>
  struct hostent *gethostbyname(const char *name);
很明白的是,他返回一个指向 struct hostent 的指针。这个数据结构是 这样的:
  struct hostent {
    char  *h_name;
    char  **h_aliases;
    int   h_addrtype;
    int   h_length;
   char  **h_addr_list;
  };
  #define h_addr h_addr_list[0]
这里是这个数据结构的详细资料: struct hostent:
h_name - Official name of the host.
h_aliases - A NULL-terminated array of alternate names for the host.
h_addrtype - The type of address being returned; usually AF_INET.
h_length - The length of the address in bytes.
h_addr_list - A zero-terminated array of network addresses for the host. Host addresses are in Network Byte Order.
h_addr - The first address in h_addr_list.
gethostbyname() 成功时返回一个指向 struct hostent 的 指针,或者是个空 (NULL) 指针。(但是和以前不同,errno 不设置,h_errno 设置错误信息。请看下面的 herror()。)
但是如何使用呢? 这个函数可不象他看上去那么难用。
这里是个例子:
  #include <stdio.h>
  #include <stdlib.h>
  #include <errno.h>
  #include <netdb.h>
  #include <sys/types.h>
  #include <netinet/in.h>
  int main(int argc, char *argv[])
  {
    struct hostent *h;
    if (argc != 2) { /* error check the command line */
      fprintf(stderr,"usage: getip address\n");
      exit(1);
    }
    if ((h=gethostbyname(argv[1])) == NULL) { /* get the host info */
      herror("gethostbyname");
      exit(1);
    }
    printf("Host name : %s\n", h->h_name);
    printf("IP Address : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr)));
    return 0;
  }
在使用 gethostbyname() 的时候,你不能用 perror() 打印错误信息(因 为 errno 没有使用),你应该调用 herror()。
相当简单,你只是传递一个保存机器名的自负串(例如 "whitehouse.gov") 给 gethostbyname(),然后从返回的数据结构 struct hostent 中 收集信息。
唯一让人迷惑的是打印 IP 地址信息。h->h_addr 是一个 char *, 但是 inet_ntoa() 需要的是 struct in_addr。因此,我 转换 h->h_addr 成 struct in_addr *,然后得到数据。