gethostbyname函数和getservbyname函数的应用

本文介绍如何利用TCP客户端/服务器模式实现时间信息的获取。具体包括gethostbyname和服务发现函数getservbyname的使用,以及服务器端和客户端的代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*******************************************************************************
函数原型: struct hostent* gethostbyname(const char* name)
函数说明:通过主机名调用gethostbyname返回包含主机正式名称,主机别名,IPV4地址等信息的结构体
返回值: 若成功返回struct hostent*,出错返回NULL,并修改全局变量h_errno,不修改errno
**********************************************************************************/

/***********************************************************************************
struct hostent {
char* h_name;//主机正式规范名称
char** h_aliases;//主机别名
int h_addrtype; //主机地址类型
int h_length;//地址长度
char** h_addr_list;//地址列表(IPV4)
}
***********************************************************************************/

/***********************************************************************************
函数原型: struct servent* getservbyname(const char* name,const char*protoname)
函数说明:通过服务名+使用协议(若为NULL,得到结构体采用协议依赖实现),得到包含正式服务名,服务别名,服务端口,服务使用协议等信息的结构体
返回值:若成功,返回struct servent*,若失败,返回NULL
***********************************************************************************/

/**********************************************************************************
struct servent {
char *s_name; //正式服务名
char** s_aliases;//服务名别名
char* s_port;//服务端口号
char* s_proto;//服务采用协议
}
**********************************************************************************/

应用:通过TCP C/S获取时间 :
服务器代码:(从别的主机获取时要确保它们的标准时间服务器端口已打开):

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>

#define PORT 13
#define LISTENQ 100

void sig_child(int signo) {
    int ppid;
    while ((ppid = waitpid(-1,NULL,WNOHANG)) < 0) {
        printf("waitpid error: %s\n",strerror(errno));
        exit(1);
    }
}

void server_echo(int fd) {
    char str[128];
    time_t t = time(NULL);
    strftime(str,sizeof(str),"%Y %x %X",localtime(&t));
    int len = strlen(str);
    str[len] = '\n';
    str[len + 1] = '\0';
    if (write(fd,str,strlen(str)) != strlen(str)) {
        printf("write error: %s\n",strerror(errno));
        exit(1);
    }
}

int main() {
    int sockfd;
    if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
        printf("socket error: %s\n",strerror(errno));
        exit(1);
    }

    struct sockaddr_in serveraddr;
    bzero(&serveraddr,sizeof(struct sockaddr_in));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(PORT);
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(struct sockaddr_in)) < 0) {
        printf("bind error: %s\n",strerror(errno));
        exit(1);
    }

    if (listen(sockfd,LISTENQ) < 0) {
        printf("listen error: %s\n",strerror(errno));
        exit(1);
    }

    if (signal(SIGCHLD,sig_child) == SIG_ERR) {
        printf("signal error: %s\n",strerror(errno));
        exit(1);
    }
    int connfd;
    int pid;
    for (; ;) {
        if ((connfd = accept(sockfd,NULL,NULL)) < 0) {
            if (errno == EINTR) {
                continue;
            }
            printf("accept error: %s\n",strerror(errno));
        }
        if ((pid = fork()) < 0) {
            printf("fork error: %s\n",strerror(errno));
            exit(1);
        }else if (pid == 0) {
            close(sockfd);
            server_echo(connfd);
            close(connfd);
            exit(0);
        }
        close(connfd);
    }
    return 0;
}

客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>

#define BUFSIZE 4096

int main(int argc,char **argv) {
    if (argc != 3) {
        printf("add <hostname> <serveices>\n");
        exit(1);
    }

    struct hostent* host;
    struct in_addr** ppaddr;
    struct in_addr* addr[2];
    struct in_addr initaddr;
    if ((host = gethostbyname(argv[1])) == NULL) {
        if (inet_pton(AF_INET,argv[1],&initaddr) <= 0) {
            printf("gethostbyname error: %s\n",hstrerror(h_errno));
            exit(1);
        }else {
            addr[0] = &initaddr;
            addr[1] = NULL;
            ppaddr = addr;
        }
    }else {
        ppaddr = (struct in_addr**)host->h_addr_list;
    }

    struct servent* service;
    if ((service = getservbyname(argv[2],NULL)) == NULL) {
        printf("getservbyname error\n");
        exit(1);
    }
    int sockfd;
    struct sockaddr_in serveraddr;
    bzero(&serveraddr,sizeof(struct sockaddr_in));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = service->s_port;
    for (; *ppaddr != NULL; ++ppaddr) {
        if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
            printf("socket error: %s\n",strerror(errno));
            exit(1);
        }
        memcpy(&serveraddr.sin_addr,*ppaddr,sizeof(struct in_addr));
        char str[INET_ADDRSTRLEN];
        if (inet_ntop(AF_INET,&serveraddr.sin_addr,str,sizeof(str)) == NULL) {
            printf("inet_ntop error: %s\n",strerror(errno));
            exit(1);
        }
        printf("trying to connect IP: %s  port: %d\n",str,ntohs(serveraddr.sin_port));
        if (connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(struct sockaddr_in)) == 0) {
            printf("connect to IP: %s port success: %d\n",str,ntohs(serveraddr.sin_port));
            break;
        }
        printf("connect to IP: %s port: %d failed reason: %s\n",str,ntohs(serveraddr.sin_port),strerror(errno));
    }
    if (*ppaddr == NULL) {
        printf("all connect failed\n");
    }

    char recv[BUFSIZE];
    int n;
    while ((n = read(sockfd,recv,BUFSIZE)) > 0) {
        if (write(STDOUT_FILENO,recv,n) != n) {
            printf("write error: %s\n",strerror(errno));
            exit(1);
        }
    }
    return 0;
}

运行:

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值