2024.12.16
1、通过主机名和服务名获取目标服务器上的daytime服务
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <arpa/inet.h>
int main(int argc,char *argv[]){
assert(argc==2);
char *host = argv[1];
//获取目标主机地址信息
struct hostent* hostinfo = gethostbyname(host);
char ip[128];
assert(hostinfo);
printf("host name is %s\n",hostinfo->h_name);
printf("host ip is %s\n",inet_ntop(AF_INET,hostinfo->h_addr_list,ip,INET_ADDRSTRLEN));
//获取daytime服务信息
struct servent* servinfo = getservbyname("daytime", "tcp");
assert(servinfo);
printf("daytime port is %d\n",ntohs(servinfo->s_port));
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = servinfo->s_port;
address.sin_addr = *(struct in_addr*)*hostinfo->h_addr_list;
int sockfd = socket(AF_INET,SOCK_STREAM,0);
int result = connect(sockfd,(struct sockaddr*)&address,sizeof(address));
assert(result!=-1);
char buffer[128];
result = read(sockfd,buffer,sizeof(buffer));
assert(result>0);
buffer[result] = '\0';
printf("the day item is %s\n",buffer);
close(sockfd);
return 0;
}
注意getservbyname和getservebyport函数实际上都是通过读取(本机的)/etc/services来获取服务信息的。
这里为了方便测试选择了本机hostname,不过运行结果显示的ip有点奇怪:
每次运行结果的host ip除了以192开头外都不一样,可能是返回的随机ip?
2、利用dup函数实现一个基本的CGI服务器
服务器程序:
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
int main(int argc,char *argv[]){
assert(argc==3);
const char *ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET,ip,&address.sin_addr);
int sock = socket(PF_INET,SOCK_STREAM,0);
assert(sock>=0);
int ret = bind(sock,(struct sockaddr*)&address,sizeof(address));
assert(ret!=-1);
ret = listen(sock, 5);
assert(ret!=-1);
struct sockaddr_in client;
socklen_t client_addrlength = sizeof(client);
int connfd = accept(sock, (struct sockaddr*)&client, &client_addrlength);
if(connfd<0) printf("errno is %d\n",errno);
else{
close(STDOUT_FILENO);//标准输出文件描述符STDOUT_FILENO的值是1
dup(connfd);//dup会返回系统中最小的可用的文件描述符,所以其返回值实际上是1,所以服务器标准输出的内容就会直接发送到与客户连接对应的socket上
//这就是CGI服务器的基本工作原理
printf("abcd\n");
close(connfd);
}
close(sock);
return 0;
}
客户端运行结果:
dup()函数实际上做的是创造一个新的文件描述符,该新文件描述符和原有文件描述符(形参)指向相同的文件,管道或者网络连接,这里实现重定向是利用了其返回系统当前可用的最小整数值的性质,也就是或让值为1的文件描述符重新指向了connfd指向的文件,而printf函数默认会向值为1的文件描述符指向的文件输出。