Ví dụ C đơn giản về thực hiện một HTTP POST và sử dụng phản hồi


90

Tôi muốn tạo một ứng dụng C rất đơn giản để thực hiện một bài đăng HTTP. Nó sẽ cần một vài tham số và sử dụng những tham số này để tạo URL. Tôi chỉ muốn thực hiện một HTTP POST đơn giản và nhận phản hồi mà không cần sử dụng curl (các thư viện không và sẽ không được cài đặt trên máy cần chạy).

Mã giả:

  1. Xử lý 2 args

  2. Đặt các args vào URL mẫu: http://api.somesite.com/apikey=ARG1&command=ARG2

  3. ĐĂNG trên URL đã tạo

  4. Tiêu thụ phản hồi

Các tìm kiếm trên Google và SO của tôi không mang lại kết quả gì về vấn đề này.


2
Bạn có sử dụng bất kỳ loại khung mạng nào không? Bạn sử dụng hệ điều hành nào?
cnicutar

Nó sẽ chỉ là một hộp Fedora hoặc Cent cơ bản. Các khung mạng là sys / socket, netdb, arpa / inet thông thường. Chỉ không libcurl.
kmarks2

1
Không phải libcurl. Bạn có sẵn sàng sử dụng bất kỳ thư viện nào khác không hay nó phải là all-POSIX.
cnicutar

Thật không may, tất cả POSIX. Nó phải được đứng hoàn toàn tự do trên bất kỳ hệ thống nào.
kmarks

2
Tôi có một mẫu tôi đã làm cho bạn nhưng tôi không hiểu tại sao bạn lại sử dụng POST nếu không có nội dung cho thư. Nếu tất cả các tham số nằm trong chuỗi truy vấn tại sao bạn không muốn thực hiện GET?
Jerry Jeremiah

Câu trả lời:


191

Thư có phần tiêu đề và phần nội dung thư được phân tách bằng một dòng trống. Dòng trống LUÔN LUÔN cần thiết ngay cả khi không có nội dung thư. Tiêu đề bắt đầu bằng một lệnh và có các dòng bổ sung của các cặp giá trị khóa được phân tách bằng dấu hai chấm và dấu cách. Nếu có một nội dung thư, nó có thể là bất cứ thứ gì bạn muốn.

Các dòng trong tiêu đề và dòng trống ở cuối tiêu đề phải kết thúc bằng cặp dòng trả về và nguồn cấp dữ liệu dòng (xem kiểu ngắt dòng tiêu đề HTTP ), đó là lý do tại sao các dòng đó có \ r \ n ở cuối.

URL có dạng http://host:port/path?query_string

Có hai cách chính để gửi yêu cầu đến một trang web:

  • GET: Chuỗi truy vấn là tùy chọn nhưng, nếu được chỉ định, phải ngắn hợp lý. Do đó, tiêu đề chỉ có thể là lệnh GET và không có gì khác. Một thông báo mẫu có thể là:

    GET /path?query_string HTTP/1.0\r\n
    \r\n
    
  • ĐĂNG: Thay vào đó, những gì thường có trong chuỗi truy vấn nằm trong phần nội dung của thư. Do đó, tiêu đề cần phải bao gồm các thuộc tính Content-Type: và Content-Length: cũng như lệnh POST. Một thông báo mẫu có thể là:

    POST /path HTTP/1.0\r\n
    Content-Type: text/plain\r\n
    Content-Length: 12\r\n
    \r\n
    query_string
    

Vì vậy, để trả lời câu hỏi của bạn: nếu URL mà bạn muốn ĐĂNG đến là http://api.somesite.com/apikey=ARG1&command=ARG2 thì không có nội dung hoặc chuỗi truy vấn và do đó, không có lý do gì để ĐĂNG vì ở đó không có gì để đưa vào nội dung thư và vì vậy không có gì để đưa vào Loại nội dung: và Nội dung-Độ dài:

Tôi đoán bạn có thể ĐĂNG nếu bạn thực sự muốn. Trong trường hợp đó, tin nhắn của bạn sẽ giống như sau:

POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
\r\n

Vì vậy, để gửi thông điệp, chương trình C cần:

  • tạo một ổ cắm
  • tra cứu địa chỉ IP
  • mở ổ cắm
  • gửi yêu cầu
  • đợi phản hồi
  • đóng ổ cắm

Cuộc gọi gửi và nhận sẽ không nhất thiết phải gửi / nhận TẤT CẢ dữ liệu bạn cung cấp cho họ - chúng sẽ trả về số byte thực sự đã gửi / nhận. Bạn có thể gọi điện theo vòng lặp và gửi / nhận phần còn lại của tin nhắn.

Những gì tôi đã không làm trong mẫu này là bất kỳ loại kiểm tra lỗi thực sự nào - khi có điều gì đó không thành công, tôi chỉ cần thoát khỏi chương trình. Hãy cho tôi biết nếu nó làm việc cho bạn:

#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */

void error(const char *msg) { perror(msg); exit(0); }

int main(int argc,char *argv[])
{
    /* first what are we going to send and where are we going to send it? */
    int portno =        80;
    char *host =        "api.somesite.com";
    char *message_fmt = "POST /apikey=%s&command=%s HTTP/1.0\r\n\r\n";

    struct hostent *server;
    struct sockaddr_in serv_addr;
    int sockfd, bytes, sent, received, total;
    char message[1024],response[4096];

    if (argc < 3) { puts("Parameters: <apikey> <command>"); exit(0); }

    /* fill in the parameters */
    sprintf(message,message_fmt,argv[1],argv[2]);
    printf("Request:\n%s\n",message);

    /* create the socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");

    /* lookup the ip address */
    server = gethostbyname(host);
    if (server == NULL) error("ERROR, no such host");

    /* fill in the structure */
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);

    /* connect the socket */
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");

    /* send the request */
    total = strlen(message);
    sent = 0;
    do {
        bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total);

    /* receive the response */
    memset(response,0,sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    do {
        bytes = read(sockfd,response+received,total-received);
        if (bytes < 0)
            error("ERROR reading response from socket");
        if (bytes == 0)
            break;
        received+=bytes;
    } while (received < total);

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);

    /* process response */
    printf("Response:\n%s\n",response);

    return 0;
}

Giống như câu trả lời khác đã chỉ ra, 4096 byte không phải là một phản hồi quá lớn. Tôi đã chọn con số đó một cách ngẫu nhiên với giả định rằng phản hồi cho yêu cầu của bạn sẽ ngắn. Nếu nó có thể lớn, bạn có hai lựa chọn:

  • đọc tiêu đề Content-Length: từ phản hồi và sau đó tự động phân bổ đủ bộ nhớ để chứa toàn bộ phản hồi.
  • ghi phản hồi vào một tệp khi các phần đến

Thông tin bổ sung để trả lời câu hỏi được hỏi trong phần bình luận:

Điều gì xảy ra nếu bạn muốn ĐĂNG dữ liệu trong phần nội dung thư? Sau đó, bạn cần bao gồm tiêu đề Content-Type: và Content-Length:. Nội dung-Độ dài: là độ dài thực tế của mọi thứ sau dòng trống ngăn cách tiêu đề khỏi nội dung.

Đây là một mẫu lấy các đối số dòng lệnh sau:

  • tổ chức
  • Hải cảng
  • lệnh (GET hoặc POST)
  • đường dẫn (không bao gồm dữ liệu truy vấn)
  • dữ liệu truy vấn (đưa vào chuỗi truy vấn cho GET và vào phần nội dung cho POST)
  • danh sách các tiêu đề (Nội dung-Độ dài: là tự động nếu sử dụng POST)

Vì vậy, đối với câu hỏi ban đầu, bạn sẽ chạy:

a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"

Và đối với câu hỏi được hỏi trong phần bình luận, bạn sẽ chạy:

a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded"

Đây là mã:

#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit, atoi, malloc, free */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */

void error(const char *msg) { perror(msg); exit(0); }

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

    /* first where are we going to send it? */
    int portno = atoi(argv[2])>0?atoi(argv[2]):80;
    char *host = strlen(argv[1])>0?argv[1]:"localhost";

    struct hostent *server;
    struct sockaddr_in serv_addr;
    int sockfd, bytes, sent, received, total, message_size;
    char *message, response[4096];

    if (argc < 5) { puts("Parameters: <host> <port> <method> <path> [<data> [<headers>]]"); exit(0); }

    /* How big is the message? */
    message_size=0;
    if(!strcmp(argv[3],"GET"))
    {
        message_size+=strlen("%s %s%s%s HTTP/1.0\r\n");        /* method         */
        message_size+=strlen(argv[3]);                         /* path           */
        message_size+=strlen(argv[4]);                         /* headers        */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* query string   */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        message_size+=strlen("\r\n");                          /* blank line     */
    }
    else
    {
        message_size+=strlen("%s %s HTTP/1.0\r\n");
        message_size+=strlen(argv[3]);                         /* method         */
        message_size+=strlen(argv[4]);                         /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        if(argc>5)
            message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */
        message_size+=strlen("\r\n");                          /* blank line     */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* body           */
    }

    /* allocate space for the message */
    message=malloc(message_size);

    /* fill in the parameters */
    if(!strcmp(argv[3],"GET"))
    {
        if(argc>5)
            sprintf(message,"%s %s%s%s HTTP/1.0\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                strlen(argv[4])>0?argv[4]:"/",                 /* path           */
                strlen(argv[5])>0?"?":"",                      /* ?              */
                strlen(argv[5])>0?argv[5]:"");                 /* query string   */
        else
            sprintf(message,"%s %s HTTP/1.0\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                strlen(argv[4])>0?argv[4]:"/");                /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        strcat(message,"\r\n");                                /* blank line     */
    }
    else
    {
        sprintf(message,"%s %s HTTP/1.0\r\n",
            strlen(argv[3])>0?argv[3]:"POST",                  /* method         */
            strlen(argv[4])>0?argv[4]:"/");                    /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        if(argc>5)
            sprintf(message+strlen(message),"Content-Length: %d\r\n",strlen(argv[5]));
        strcat(message,"\r\n");                                /* blank line     */
        if(argc>5)
            strcat(message,argv[5]);                           /* body           */
    }

    /* What are we going to send? */
    printf("Request:\n%s\n",message);

    /* create the socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");

    /* lookup the ip address */
    server = gethostbyname(host);
    if (server == NULL) error("ERROR, no such host");

    /* fill in the structure */
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);

    /* connect the socket */
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");

    /* send the request */
    total = strlen(message);
    sent = 0;
    do {
        bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total);

    /* receive the response */
    memset(response,0,sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    do {
        bytes = read(sockfd,response+received,total-received);
        if (bytes < 0)
            error("ERROR reading response from socket");
        if (bytes == 0)
            break;
        received+=bytes;
    } while (received < total);

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);

    /* process response */
    printf("Response:\n%s\n",response);

    free(message);
    return 0;
}

Những đối số nào nên được chuyển khi được gọi?
Santiago Martí Olbrich

Bạn cần chuyển một thứ gì đó sẽ được sử dụng làm apikey làm tham số đầu tiên và một thứ gì đó trong tham số thứ hai sẽ được sử dụng làm lệnh. Nếu bạn muốn sử dụng một chuỗi truy vấn hoàn toàn khác thì bạn cần thay đổi chuỗi định dạng, số lượng tham số và thông báo sử dụng.
Jerry Jeremiah

2
Mã này tạo ra một yêu cầu HTTP không đúng định dạng. HTTP chỉ định rằng các dòng yêu cầu phải được kết thúc bằng cặp ký tự xuống dòng / dòng cấp ( \r\n), nhưng mã này sử dụng nguồn cấp dữ liệu dòng trần.
John Bollinger

@JohnBollinger Điều đó rất đúng. Cảm ơn đã chỉ ra điều đó. Hy vọng rằng câu trả lời đã được chỉnh sửa sẽ tốt hơn.
Jerry Jeremiah

Có gì sai với bài viết này? "POST /variableName=%s&value=%s HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 4\r\n\r\n\r\n"Tôi muốn đăng giống như tên = reaz. Nó phản hồi 400 yêu cầu không hợp lệ
Reaz Murshed

12

Câu trả lời của Jerry thật tuyệt. Tuy nhiên, nó không xử lý các phản hồi lớn. Một thay đổi đơn giản để xử lý điều này:

memset(response, 0, sizeof(response));
total = sizeof(response)-1;
received = 0;
do {
    printf("RESPONSE: %s\n", response);
    // HANDLE RESPONSE CHUCK HERE BY, FOR EXAMPLE, SAVING TO A FILE.
    memset(response, 0, sizeof(response));
    bytes = recv(sockfd, response, 1024, 0);
    if (bytes < 0)
        printf("ERROR reading response from socket");
    if (bytes == 0)
        break;
    received+=bytes;
} while (1); 

3
Bạn chỉ có thể làm cho mảng phản hồi trong ví dụ của tôi lớn hơn. Tôi đã giả định ông chỉ nhận lại một số json và không tải một tập tin rất lớn nhưng tất nhiên thậm chí json có thể MB tùy thuộc vào truy vấn ...
Jerry Jeremiah

1
Tôi là người mới bắt đầu học C và câu trả lời của bạn có thể đúng. Nhưng bạn có thể vui lòng thêm một lời giải thích cho câu trả lời của bạn?
boop

2
Đây thực sự chỉ là một nhận xét về câu trả lời được chấp nhận, và không nên được thực hiện như một nỗ lực riêng để trả lời.
Michael Gaskill

1
Chỉ cần thêm một điều ở đây, điều này hoạt động tuyệt vời tuy nhiên bạn nên đọc kích thước của bộ đệm - 1 byte. Và để xem nó đúng cách, tôi sẽ không sử dụng một dòng mới trong câu lệnh in đó. Nên xem xét như thế này:bytes = recv(sockfd, response, 1023, 0)
xjsc16x

11

Sau nhiều tuần nghiên cứu. Tôi đã nghĩ ra đoạn mã sau. Tôi tin rằng đây là mức tối thiểu cần thiết để tạo kết nối an toàn bằng SSL với máy chủ web.

#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>

#define APIKEY "YOUR_API_KEY"
#define HOST "YOUR_WEB_SERVER_URI"
#define PORT "443"

int main() {

    //
    //  Initialize the variables
    //
    BIO* bio;
    SSL* ssl;
    SSL_CTX* ctx;

    //
    //   Registers the SSL/TLS ciphers and digests.
    //
    //   Basically start the security layer.
    //
    SSL_library_init();

    //
    //  Creates a new SSL_CTX object as a framework to establish TLS/SSL
    //  or DTLS enabled connections
    //
    ctx = SSL_CTX_new(SSLv23_client_method());

    //
    //  -> Error check
    //
    if (ctx == NULL)
    {
        printf("Ctx is null\n");
    }

    //
    //   Creates a new BIO chain consisting of an SSL BIO
    //
    bio = BIO_new_ssl_connect(ctx);

    //
    //  Use the variable from the beginning of the file to create a 
    //  string that contains the URL to the site that you want to connect
    //  to while also specifying the port.
    //
    BIO_set_conn_hostname(bio, HOST ":" PORT);

    //
    //   Attempts to connect the supplied BIO
    //
    if(BIO_do_connect(bio) <= 0)
    {
        printf("Failed connection\n");
        return 1;
    }
    else
    {
        printf("Connected\n");
    }

    //
    //  The bare minimum to make a HTTP request.
    //
    char* write_buf = "POST / HTTP/1.1\r\n"
                      "Host: " HOST "\r\n"
                      "Authorization: Basic " APIKEY "\r\n"
                      "Connection: close\r\n"
                      "\r\n";

    //
    //   Attempts to write len bytes from buf to BIO
    //
    if(BIO_write(bio, write_buf, strlen(write_buf)) <= 0)
    {
        //
        //  Handle failed writes here
        //
        if(!BIO_should_retry(bio))
        {
            // Not worth implementing, but worth knowing.
        }

        //
        //  -> Let us know about the failed writes
        //
        printf("Failed write\n");
    }

    //
    //  Variables used to read the response from the server
    //
    int size;
    char buf[1024];

    //
    //  Read the response message
    //
    for(;;)
    {
        //
        //  Get chunks of the response 1023 at the time.
        //
        size = BIO_read(bio, buf, 1023);

        //
        //  If no more data, then exit the loop
        //
        if(size <= 0)
        {
            break;
        }

        //
        //  Terminate the string with a 0, to let know C when the string 
        //  ends.
        //
        buf[size] = 0;

        //
        //  ->  Print out the response
        //
        printf("%s", buf);
    }

    //
    //  Clean after ourselves
    //
    BIO_free_all(bio);
    SSL_CTX_free(ctx);

    return 0;
}

Đoạn mã trên sẽ giải thích chi tiết cách thiết lập kết nối TLS với máy chủ từ xa.

Lưu ý quan trọng : mã này không kiểm tra xem khóa công khai đã được ký bởi cơ quan hợp lệ hay chưa. Có nghĩa là tôi không sử dụng chứng chỉ gốc để xác thực. Đừng quên thực hiện kiểm tra này nếu không bạn sẽ không biết mình có đang kết nối đúng trang web hay không

Khi nói đến yêu cầu của chính nó. Không có gì khác hơn sau đó viết yêu cầu HTTP bằng tay.

Bạn cũng có thể tìm thấy dưới liên kết này giải thích cách cài đặt openSSL trong hệ thống của bạn và cách biên dịch mã để nó sử dụng thư viện an toàn .


2
Giải thích tốt đẹp!
Satyam Koyani,

không, biến tiếp theo là cổng, chúng tôi đã kết nối với cổng bên phải.
David Gatti

3

Đã thêm xử lý.
Đã thêm tiêu đề Máy chủ.
Đã thêm hỗ trợ linux / windows, đã thử nghiệm (XP, WIN7).
CẢNH BÁO: LỖI: "lỗi phân đoạn" nếu không có máy chủ, đường dẫn hoặc cổng làm đối số.

#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit, atoi, malloc, free */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#ifdef __linux__ 
    #include <sys/socket.h> /* socket, connect */
    #include <netdb.h> /* struct hostent, gethostbyname */
    #include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#elif _WIN32
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <windows.h>
    #pragma comment(lib,"ws2_32.lib") //Winsock Library

#else

#endif

void error(const char *msg) { perror(msg); exit(0); }

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

    int i;
    struct hostent *server;
    struct sockaddr_in serv_addr;
    int bytes, sent, received, total, message_size;
    char *message, response[4096];
    int portno = atoi(argv[2])>0?atoi(argv[2]):80;
    char *host = strlen(argv[1])>0?argv[1]:"localhost";
    char *path = strlen(argv[4])>0?argv[4]:"/";
    if (argc < 5) { puts("Parameters: <host> <port> <method> <path> [<data> [<headers>]]"); exit(0); }
    /* How big is the message? */
    message_size=0;
    if(!strcmp(argv[3],"GET"))
    {
                printf("Process 1\n");
        message_size+=strlen("%s %s%s%s HTTP/1.0\r\nHost: %s\r\n");        /* method         */
        message_size+=strlen(argv[3]);                         /* path           */
        message_size+=strlen(path);                         /* headers        */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* query string   */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        message_size+=strlen("\r\n");                          /* blank line     */
    }
    else
    {
                printf("Process 2\n");
        message_size+=strlen("%s %s HTTP/1.0\r\nHost: %s\r\n");
        message_size+=strlen(argv[3]);                         /* method         */
        message_size+=strlen(path);                            /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        if(argc>5)
            message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */
        message_size+=strlen("\r\n");                          /* blank line     */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* body           */
    }
            printf("Allocating...\n");
    /* allocate space for the message */
    message=malloc(message_size);

    /* fill in the parameters */
    if(!strcmp(argv[3],"GET"))
    {
        if(argc>5)
            sprintf(message,"%s %s%s%s HTTP/1.0\r\nHost: %s\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                path,                                          /* path           */
                strlen(argv[5])>0?"?":"",                      /* ?              */
                strlen(argv[5])>0?argv[5]:"",host);            /* query string   */
        else
            sprintf(message,"%s %s HTTP/1.0\r\nHost: %s\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                path,host);                                    /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        strcat(message,"\r\n");                                /* blank line     */
    }
    else
    {
        sprintf(message,"%s %s HTTP/1.0\r\nHost: %s\r\n",
            strlen(argv[3])>0?argv[3]:"POST",                  /* method         */
            path,host);                                        /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        if(argc>5)
            sprintf(message+strlen(message),"Content-Length: %d\r\n",(int)strlen(argv[5]));
        strcat(message,"\r\n");                                /* blank line     */
        if(argc>5)
            strcat(message,argv[5]);                           /* body           */
    }
    printf("Processed\n");
    /* What are we going to send? */
    printf("Request:\n%s\n",message);
        /* lookup the ip address */

    total = strlen(message);
    /* create the socket */
    #ifdef _WIN32
WSADATA wsa;
SOCKET s;

printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
    printf("Failed. Error Code : %d",WSAGetLastError());
    return 1;
}

printf("Initialised.\n");

//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
    printf("Could not create socket : %d" , WSAGetLastError());
}

printf("Socket created.\n");

server = gethostbyname(host);
serv_addr.sin_addr.s_addr = inet_addr(server->h_addr);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
//Connect to remote server
if (connect(s , (struct sockaddr *)&serv_addr , sizeof(serv_addr)) < 0)
{
    printf("connect failed with error code : %d" , WSAGetLastError());
    return 1;
}

puts("Connected");
if( send(s , message , strlen(message) , 0) < 0)
{
    printf("Send failed with error code : %d" , WSAGetLastError());
    return 1;
}
puts("Data Send\n");

//Receive a reply from the server
if((received = recv(s , response , 2000 , 0)) == SOCKET_ERROR)
{
    printf("recv failed with error code : %d" , WSAGetLastError());
}

puts("Reply received\n");

//Add a NULL terminating character to make it a proper string before printing
response[received] = '\0';
puts(response);

closesocket(s);
WSACleanup();
    #endif
    #ifdef __linux__ 
    int sockfd;
    server = gethostbyname(host);
    if (server == NULL) error("ERROR, no such host");
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) error("ERROR opening socket");
        /* fill in the structure */
        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(portno);
        memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
                /* connect the socket */
        if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
            error("ERROR connecting");
                /* send the request */

    sent = 0;
    do {
        bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total);
    /* receive the response */
    memset(response, 0, sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    printf("Response: \n");
    do {
       printf("%s", response);
       memset(response, 0, sizeof(response));
       bytes = recv(sockfd, response, 1024, 0);
        if (bytes < 0)
           printf("ERROR reading response from socket");
       if (bytes == 0)
           break;
       received+=bytes;
    } while (1);

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);
    #endif


    free(message);

    return 0;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.