通过服务器的名字而不是服务器端口号来认知它,而且如果从主机到端口号的映射包含在一个文件中(一般是/etc/services),则如果端口号改变,我们所需做的所有改动就是改动文件/etc/services中的一行,而不是重新编译应用程序。
getservbyname函数原型为:
#include <netdb.h> struct servent *getservbyname(const char *servname, const char *protoname);成功返回非空指针,失败返回空指针
此函数返回一个指向下面所示结构的指针:
struct servent { char *s_name; //official service name char **s_aliases; // alias list int s_port;// port number, network-byte order char *s_proto;// protocol to use };
结构servent中我们关心的主要成员是端口号,由于端口号是以网络字节序返回的,在将它存储于套接口地址结构时,绝对不能调用htons
对此函数的典型调用是:
struct servent *sptr; sptr = getservbyname("domain", "udp"); // DNS using UDP sptr = getservbyname("ftp", "tcp");//FTP using TCP sptr = getservbyname("ftp", NULL); //FTP using TCP sptr = getservbyname("ftp", "udp");// this call will fail由于FTP仅支持TCP,所以第二个和第三个调用 是相同的,第四个调用将失败。
下一个函数getservbyport在给定端口号和可选协议后查找相应的服务
#include <netdb.h> struct servent *getservbyport(int port, const char *protoname);成功返回非空指针,失败返回空指针
port为网络字节序。对此函数的典型调用是:
struct servent *sptr; sptr = getservbyport(htons(53), "udp"); // DNS using UDP sptr = getservbyport(htons(21), "tcp");//FTP using TCP sptr = getservbyport(htons(21), NULL);//FTP using TCP sptr = getservbyport(htons(21), "udp");// this call will fail
代码如下:
#include <netdb.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAXLINE 128 char *sock_ntop(const struct sockaddr* sa, socklen_t salen) { char portstr[7]; static char str[MAXLINE]; switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in*)sa; if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) return NULL; if (ntohs(sin->sin_port) != 0) { snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port)); strcat(str, portstr); } return str; } } } int main(int argc, char **argv) { int sockfd, n; char recvline[MAXLINE + 1]; struct sockaddr_in servaddr; struct in_addr **pptr; struct hostent *hp; struct servent *sp; if (argc != 3) { printf("usage: execname <hostname> <service> \n"); return -1; } if ((hp = gethostbyname(argv[1])) == NULL) { printf("hostname error for %s:%s\n", argv[1], hstrerror(h_errno)); return -1; } if ((sp = getservbyname(argv[2], "tcp")) == NULL) { printf("getservbyname error for %s:%s\n", argv[2], hstrerror(h_errno)); return -1; } pptr = (struct in_addr**)hp->h_addr_list; for (; *pptr != NULL; pptr++) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { printf("socket error:%s\n", strerror(errno)); return -1; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = sp->s_port; memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr)); printf("addr=%s, port=%d\n", inet_ntoa(**pptr), ntohs(sp->s_port)); printf("trying %s\n", sock_ntop((struct sockaddr*)&servaddr, sizeof(servaddr))); if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == 0) break; printf("connect error:%s\n", strerror(errno)); close(sockfd); } if (*pptr == NULL) { printf("unable to connect\n"); return -1; } while ((n = read(sockfd, recvline, MAXLINE)) > 0) { recvline[n] = 0; fputs(recvline, stdout); } return 0; }