LINUX 入门 7

LINUX 入门 7

day10 20240506 耗时:59min

day11 20240507 耗时:106min

课程链接地址

第7章 http客户端请求

1 http项目介绍与Http协议讲解

先去看一遍教程 扫一遍,不用完全一行行读

ctrl+shift+I调出来网页调试台——network——img

过程

  1. client 浏览器建立与百度服务器的tcp连接(用DNS翻译成ip)
  2. 在tcp 连接socket上发送http协议请求request(连接IP地址端口)
  3. 百度server在tcp的socket连接上返回一个http协议相应response

LINUX 入门 7_第1张图片

头部字段名有好多好多好多

2 http项目,hostname转换ip

  1. struct hostent *host_entry = gethostbyname(hostname);

    它接受一个字符串类型的主机名作为参数,并返回相应主机的 IP 地址。

    这个函数使用了 gethostbyname 函数来获取指定主机名对应的 struct hostent 结构体。该结构体包含了与主机名相关联的信息,包括 IP 地址等。

    但需要注意的是,gethostbyname 函数在一些操作系统中已经被标记为过时(deprecated),推荐使用 getaddrinfo 函数来替代。如果你正在开发新项目或者进行更新,建议考虑使用更现代化的方法来获取主机名对应的 IP 地址。

// 1 不像上次DNS翻译太麻烦,直接用接口gethostbyname
char *host_to_ip(const char* hostname){
    struct hostent *host_entry = gethostbyname(hostname);

    // 点分十进制, 14.215.177.39--->unsigned int
    //  inet_ntoa: unsigned int-->char *    0x121212--->"18.18.18.18"
    if(host_entry) return  inet_ntoa((struct in_addr*)host_entry->h_addr_list); 
    return NULL;

}

3 http项目tcp socket链接

TCP连接必须先建立一个socket

  1. struct sockaddr_in 多年没变,接口pasca api很稳定,即使内核升级,应用没事

  2. 阻塞

    if socket阻塞,read()时,一旦socket里没数据,整个线程挂起等io数据来

    if 非阻塞,立马返回,线程不会挂起

    一般选非阻塞IO

    调用 fcntl(sockfd, F_SETFL, O_NONBLOCK) 的作用是将 sockfd 所代表的套接字文件描述符设置为非阻塞模式。这意味着在进行读写操作时,它不会阻塞等待结果返回,而是立即返回。

// 2 连接服务器
int http_create_socket(char *ip){
    // TCP连接必须先建立一个socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sin = {0};
    sin.sin_family = AF_INET;
    sin.sin_port= htons(80);
    sin.sin_addr = inet_addr(ip); //ip变成域名反过来
    
	if (0 != connect(sockfd, (struct sockaddr*)&sin, sizeof(struct sockaddr_in))) {
		return -1;
	}
    fcntl(sockfd, F_SETFL, O_NONBLOCK); //阻塞非阻塞

	return sockfd;
}

4 http项目 send http请求

查pdf——客户端请求消息

1.\r\n 是两个特殊字符的组合,表示回车(Carriage Return)和换行(Line Feed),常用于文本文件中的换行符。它们在不同的操作系统中有不同的使用方式:

  • 在 Unix/Linux 系统中,通常使用 \n 作为换行符。
  • 在 Windows 系统中,通常使用 \r\n 作为换行符。
  • 在老式 Macintosh 系统中,通常使用 \r 作为换行符。

所以,当你需要跨平台编写代码时,在文本处理或网络传输中都建议使用 \r\n 作为换行符,这样可以保证在各种操作系统上正确解析和显示换行。

  1.     sprintf(buffer, 
        "GET %s %s\r\n
        HOST: %s\r\n,
        %s\r\n\
        \r\n",
        resource, HTTP_VERSION, 
        hostname,
        CONNETION_TYPE
        );
    
    
    • %s 是一个占位符,用于替代 resource、HTTP_VERSION、hostname 和 CONNECTION_TYPE 变量的值。

3 send(sockfd,buffer, strlen(buffer), 0);

  • sockfd 是已连接套接字的文件描述符。

  • buffer 是要发送的数据缓冲区。

  • strlen(buffer) 表示要发送的数据长度(以字节为单位)。

  • 0 是可选参数 flags,表示额外选项,默认设置为 0。

    // 3 请求http
    // hostname: github.com
    // resource /wangbojing
    char * http_send_request(const char *hostname, const char *resource) {
        char *ip = host_to_ip(hostname); //name-->ip
        int sockfd = http_create_socket(ip); //创建一个socket tcp连接
    
        char buffer[BUFFER_SIZE] ={0};
        sprintf(buffer, 
        "GET %s %s\r\n
        HOST: %s\r\n,
        %s\r\n\
        \r\n",
        resource, HTTP_VERSION, 
        hostname,
        CONNETION_TYPE
        );
    
        send(sockfd,buffer, strlen(buffer), 0);
    
        // 获取response, 因为非阻塞,可能还没返回所以recv是空的
    }
    

5 http项目 select使用讲解与http response接收

select监听判断 网络IO里有没有可读数据

多次recv拼起来到result 好多网络编程看不懂查

  1. fd_set fdread;, 
    FD_ZERO(&fdread);
    FD_SET(sockfd, &fread);
    

    这段代码是用于设置一个文件描述符集合,然后将 sockfd(socket 文件描述符)添加到该集合中。

    首先,fd_set fdread; 定义了一个文件描述符集合 fdread。

    接下来,FD_ZERO(&fdread); 会将 fdread 集合清空,初始化为空集。

    最后,FD_SET(sockfd, &fread); 将 sockfd 添加到 fdread 集合中。此操作表示将 sockfd 加入到待检查的读取文件描述符集合中。

    这段代码通常在使用 select() 或 epoll() 等 I/O 多路复用函数时使用,用于指定要监视的文件描述符。

  2. int selection = select(sockfd+1, fread, NULL, NULL, &tv); // 可读maxfd+1, 可读集合&rset,可写集合&wset, 错误集合&eset, 多长时间遍历一次所有IO 
    		if (!selection || !FD_ISSET(sockfd, &fdread)) {
    			break;
    		} else{
                memset(buffer,  0, BUFFER_SIZE);
                recv(sockfd, buffer, BUFFER_SIZE, 0); //sockfd读到buffer
                if(len ==0) break; //disconnect
            }
            result = realloc(result, (strlen(result) + len + 1) * sizeof(char));
            strncat(result, buffer, len);
    

    这段代码是一个基于 select() 函数的网络编程示例,用于检测套接字 sockfd 是否可读。下面是代码的解释:

    1. int selection = select(sockfd+1, fread, NULL, NULL, &tv); 这行代码调用了 select() 函数来等待 sockfd 的可读事件。第一个参数是文件描述符最大值加 1,表示要监视的最大文件描述符数(sockfd+1)。第二个参数是可读集合,即包含 sockfd 的 fd_set 结构体指针(fread)。
    2. if (!selection || !FD_ISSET(sockfd, &fdread)) { break; } 这个条件判断语句会在 select() 返回之后进行处理。如果 select() 返回值为 0 或者 sockfd 不在可读集合中,则跳出循环。
    3. memset(buffer, 0, BUFFER_SIZE); recv(sockfd, buffer, BUFFER_SIZE, 0); 这两行代码将 buffer 数组清零,并通过 recv() 函数从 sockfd 接收数据存入 buffer 中。
    4. if (len == 0) break; 如果 len(recv() 返回的结果)等于 0,说明连接已经断开,跳出循环。
    5. result = realloc(result, (strlen(result) + len + 1) * sizeof(char)); strncat(result, buffer, len); 这两行代码用于动态扩展 result 字符串,并将接收到的数据追加到 result 中。realloc() 函数重新分配了足够大小的内存空间来容纳 result 和 buffer 的内容,然后使用 strncat() 函数将 buffer 中的数据追加到 result 的末尾。

    总体来说,这段代码是一个基本的网络编程示例,使用 select() 函数实现了非阻塞式读取 sockfd 上的数据,并将接收到的数据存储在 result 字符串中。

//接上一次的函数里继续
    // 3 获取response, 因为非阻塞,可能还没返回所以recv是空的
    // select
    fd_set fdread;, 
    FD_ZERO(&fdread);
    FD_SET(sockfd, &fread);

    struct timeval tv;
    tv.tv_sec = 5; //等待秒数
    tv.tv_usec = 0; //等待微秒数

    char *result = malloc(sizeof(int));  //malloc的数据一定要memset0防止混乱数据,最后要free
	memset(result, 0, sizeof(int));
	

    while(1){
        int selection = select(sockfd+1, fread, NULL, NULL, &tv); // 可读maxfd+1, 可读集合&rset,可写集合&wset, 错误集合&eset, 多长时间遍历一次所有IO 
		if (!selection || !FD_ISSET(sockfd, &fdread)) {
			break;
		} else{
            memset(buffer,  0, BUFFER_SIZE);
            recv(sockfd, buffer, BUFFER_SIZE, 0); //sockfd读到buffer
            if(len ==0) break; //disconnect
        }
        result = realloc(result, (strlen(result) + len + 1) * sizeof(char));
        strncat(result, buffer, len);
    }
}

int main(int argc, char *argv[]) {

	if (argc < 3) return -1;

	char *response = http_send_request(argv[1], argv[2]);
	printf("response : %s\n", response);

	free(response);
	
}

6 http项目编译调试,网页请求与API接口请求

还行,调一下, 一个个调就行,有点耐心

gcc -o httprequest httprequest.c
./httprequest www.baidu.com /

/代表resource 首页所以只有/

没有东西 只有response:, 暂时没调出来

正常应该接受到源码网页右击view page source 或者CTRL+U

你可能感兴趣的:(LINUX入门,linux,服务器)