使用c发送GET请求

参考地址:http://www.wangafu.net/~nickm/libevent-book/01_intro.html#_footnote_1

在阅读libevent文档时发现这个例子,文档列出这个例子的重点是说明阻塞式编程。因为对C网络编程还不太懂,这里添加了一些注释。

/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For gethostbyname */
#include <netdb.h>

#include <unistd.h>
#include <string.h>
#include <stdio.h>

int main(int c, char **v)
{
	//\r表示回车,\n表示换行
	//发送这些信息,应该相当于发送了一个GET请求。利用socket来发送get请求
    const char query[] =
        "GET / HTTP/1.0\r\n"
        "Host: www.baidu.com\r\n"
        "\r\n";
    const char hostname[] = "www.baidu.com";

    //套接字地址结构,在Unix网络编程中有描述
    struct sockaddr_in socketAddr_in;

    //对一个主机的描述,有地址,主机名等
    struct hostent *baiduhost;
    const char *cp;
    int fd;
    ssize_t n_written, remaining;
    char buf[1024];

    /* Look up the IP address for the hostname.   Watch out; this isn't
       threadsafe on most platforms. */
    baiduhost = gethostbyname(hostname);		//gethostbyname是阻塞的,得不到地址不返回
    if (!baiduhost) {
        fprintf(stderr, "Couldn't lookup %s: %s", hostname, hstrerror(h_errno));
        return 1;
    }
    if (baiduhost->h_addrtype != AF_INET) {
        fprintf(stderr, "No ipv6 support, sorry.");
        return 1;
    }

    /* Allocate a new socket,Returns a file descriptor for the new socket, or -1 for errors.  */
    //the first is the address domain of the socket. recall that there are two possile address domains
    //the unic domain for two processes which share a common file system, and the internet domain for
    //any two hosts on the Internet. The symbol constant AF_UNIX is used for the former, and
    //AF_INET is used for the latter
    //第二个参数表示类型,SOCK_STREAM表示TCP,SOCK_DGRAM表示UDP
    //这个函数返回an entry into the file descriptor table (i.e. a small integer),this value is used for all
    // subsequent references to this socket
    fd = socket(AF_INET, SOCK_STREAM, 0);

    printf("fd-----> %d\n",fd);

    if (fd < 0) {
        perror("socket");
        return 1;
    }

    /* Connect to the remote host. */
    socketAddr_in.sin_family = AF_INET;
    socketAddr_in.sin_port = htons(80);
    socketAddr_in.sin_addr = *(struct in_addr*)baiduhost->h_addr;

    //connect函数,从进程到内核传递套接字地址结构的函数,第二个参数为socket指针,第三个参数为大小
    if (connect(fd, (struct sockaddr*) &socketAddr_in, sizeof(socketAddr_in))) {
        perror("connect");
        close(fd);
        return 1;
    }

    /* Write the query. */
    /* XXX Can send succeed partially? */
    //使用send和recv发送和接收数据时,都使用无限循环
    cp = query;
    remaining = strlen(query);
    while (remaining) {
      n_written = send(fd, cp, remaining, 0); //send函数,成功则返回实际传送出去的字符数,失败返回-1
      if (n_written <= 0) {
        perror("send");
        return 1;
      }
      remaining -= n_written;   //remaining 不为0表明还没有发送完数据
      cp += n_written;
    }

    /* Get an answer back. */
    //将返回结果读入到buf中,利用循环来实现读取所有的数据
    while (1) {
        ssize_t result = recv(fd, buf, sizeof(buf), 0);
        if (result == 0) { //result返回0,表示读入完毕,跳出循环
            break;
        } else if (result < 0) {
            perror("recv");
            close(fd);
            return 1;
        }
        fwrite(buf, 1, result, stdout); //写入文件或者标准输出
    }

    close(fd);
    return 0;
}


以下是一个使用C语言发送HTTP请求的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netdb.h> #define MAX_BUFFER_SIZE 1024 int main(int argc, char *argv[]) { struct sockaddr_in server_addr; struct hostent *server; int socket_fd, port_number, bytes, sent, received, total; char buffer[MAX_BUFFER_SIZE], request[MAX_BUFFER_SIZE]; if (argc < 3) { fprintf(stderr, "Usage: %s <hostname> <port_number> <path>\n", argv[0]); exit(1); } port_number = atoi(argv[2]); /* 创建 socket */ socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { perror("Failed to create socket"); exit(1); } /* 获取服务器信息 */ server = gethostbyname(argv[1]); if (server == NULL) { fprintf(stderr, "Failed to get host by name"); exit(1); } /* 初始化服务器地址结构 */ memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port_number); memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length); /* 连接服务器 */ if (connect(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("Failed to connect to server"); exit(1); } /* 构造 HTTP 请求 */ sprintf(request, "GET %s HTTP/1.1\r\nHost: %s:%d\r\nConnection: close\r\n\r\n", argv[3], argv[1], port_number); /* 发送 HTTP 请求 */ total = strlen(request); sent = 0; do { bytes = write(socket_fd, request + sent, total - sent); if (bytes < 0) { perror("Failed to send request"); exit(1); } if (bytes == 0) { break; } sent += bytes; } while (sent < total); /* 接收 HTTP 响应 */ memset(buffer, 0, sizeof(buffer)); received = 0; do { bytes = read(socket_fd, buffer + received, MAX_BUFFER_SIZE - received); if (bytes < 0) { perror("Failed to receive response"); exit(1); } if (bytes == 0) { break; } received += bytes; } while (received < MAX_BUFFER_SIZE); /* 输出 HTTP 响应 */ printf("%s\n", buffer); /* 关闭 socket */ close(socket_fd); return 0; } ``` 你可以将以上代码保存到一个名为 `http_request.c` 的文件中,并使用以下命令编译: ``` gcc http_request.c -o http_request ``` 然后在终端中运行以下命令来发送 HTTP 请求: ``` ./http_request example.com 80 / ``` 其中,`example.com` 是要请求的网站的域名,`80` 是要连接的端口号,`/` 是要请求的路径。你可以根据需要修改这些参数。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值