像主机IP地址有域名一样,服务也对应着端口号,可以在/etc/service
文件中查看,getservbyname
函数用于给定名字和协议查找相应的服务,getservbyport
函数用于根据端口号和协议查找相应的服务。
getservbyname
函数原型:
#include <netdb.h>
struct servent *getservbyname(const char *name, const char *proto);
struct servent {
char *s_name; /* 服务名 */
char **s_aliases; /* 别名 */
int s_port; /* 端口号,网络字节序 */
char *s_proto; /* 协议 */
}
getservbyport
函数原型:
struct servent *getservbyport(int port, const char *proto);
/* port 参数是网络字节序 */
运行本地daytime
服务器,然后跑daytimetcpcli1
程序,运行结果如下:
![6902163924a3e9803c42932a1868347c.png](https://i-blog.csdnimg.cn/blog_migrate/10dde8856b1b016f6d0bad41187d4901.png)
测试h3c是否开启daytime
服务,运行结果如下:
![59b2fff7b89aeee5b39da5a38cc2fe04.png](https://i-blog.csdnimg.cn/blog_migrate/82271d38de8f6c25a60ae8aa74495447.png)
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd, n;
char recvline[MAXLINE + 1];
struct sockaddr_in servaddr;
struct in_addr **pptr;
struct in_addr *inetaddrp[2];
struct in_addr inetaddr;
struct hostent *hp;
struct servent *sp;
if (argc != 3)
err_quit("usage: daytimetcpcli1 <hostname> <service>");
if ( (hp = gethostbyname(argv[1])) == NULL) {
if (inet_aton(argv[1], &inetaddr) == 0) {
err_quit("hostname error for %s: %s", argv[1], hstrerror(h_errno));
} else {
inetaddrp[0] = &inetaddr;
inetaddrp[1] = NULL;
pptr = inetaddrp;
}
} else {
pptr = (struct in_addr **) hp->h_addr_list;
}
if ( (sp = getservbyname(argv[2], "tcp")) == NULL)
err_quit("getservbyname error for %s", argv[2]);
for ( ; *pptr != NULL; pptr++) {
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
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("trying %sn",
Sock_ntop((SA *) &servaddr, sizeof(servaddr)));
if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) == 0)
break; /* success */
err_ret("connect error");
close(sockfd);
}
if (*pptr == NULL)
err_quit("unable to connect");
while ( (n = Read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
exit(0);
}
程序需要2个参数,一个主机名,一个服务名。
- 如果主机名是域名的话,那么走域名解析
gethostbyname
,拿到IPv4地址网络序 - 如果主机名是IP地址的话,那么走IPv4地址网络序
inet_aton
getservbyname
获取服务网络序端口号,尝试socket
连接每个服务器主机IPv4地址。如果connect
连接成功,就break
出循环,否则输出一个出错消息并关闭当前连接。
如果出循环没有一个connect
连接成功,就退出程序。否则,读取服务器的应答,并在服务器关闭连接后终止程序(read()
返回不大于0)。
参考文献:《UNIX网络编程 卷1:套接字联网API》