网络编程学习笔记(getservbyname和getservbyport函数)

通过服务器的名字而不是服务器端口号来认知它,而且如果从主机到端口号的映射包含在一个文件中(一般是/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
};

服务名必须指定,如果指定了一个协议(即protoname为非空指针),则结果表项也必须有匹配的协议。如果protoname没有指定且服务支持多个协议,则返回哪个端口是依赖于实现的。一般来说这没有关系,因为支持多个协议的服务常常使用相同的TCP和UDP端口号,但并没有保证

结构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;
}

输出为:

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值