日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言实现的一个简单的HTTP程序

發布時間:2025/3/21 编程问答 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言实现的一个简单的HTTP程序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以下是參考<winsock網絡編程經絡>中講解web應用http協議的時候,實現的一個簡單的http程序,包含一個服務器和一個客戶端。

先貼上客戶端的程序:

?

/*************************************************************************?* ?* Copyright (c) 2012-2013 by xuwm All Rights Reserved?*?* FILENAME:? WebClnt.c?*?* PURPOSE :? HTTP 客戶端程序, 獲取網頁.?*? ?* AUTHOR? :? 許文敏?* ?**************************************************************************/#include "stdafx.h"#include <stdio.h>#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")? /* WinSock使用的庫函數 *//* 定義常量 */#define HTTP_DEF_PORT???? 80? /* 連接的缺省端口 */#define HTTP_BUF_SIZE?? 1024? /* 緩沖區的大小?? */#define HTTP_HOST_LEN??? 256? /* 主機名長度 */char *http_req_hdr_tmpl = "GET %s HTTP/1.1\r\n"????"Accept: image/gif, image/jpeg, */*\r\nAccept-Language: zh-cn\r\n"????"Accept-Encoding: gzip, deflate\r\nHost: %s:%d\r\n"????"User-Agent: Huiyong's Browser <0.1>\r\nConnection: Keep-Alive\r\n\r\n";/**************************************************************************?*?* 函數功能: 解析命令行參數, 分別得到主機名, 端口號和文件名. 命令行格式:?*?????????? [http://www.baidu.com:8080/index.html]?*?* 參數說明: [IN]? buf, 字符串指針數組;?*?????????? [OUT] host, 保存主機;?*?????????? [OUT] port, 端口;?*?????????? [OUT] file_name, 文件名;?*?* 返 回 值: void.?*?**************************************************************************/void http_parse_request_url(const char *buf, char *host, ????????????????????????????unsigned short *port, char *file_name){????int length = 0;????char port_buf[8];????char *buf_end = (char *)(buf + strlen(buf));????char *begin, *host_end, *colon, *file;????/* 查找主機的開始位置 */?????????begin = const_cast<char*>(strstr(buf, "//"));????begin = (begin ? begin + 2 : const_cast<char*>(buf));?????????colon = strchr(begin, ':');????host_end = strchr(begin, '/');????if (host_end == NULL)????{????????host_end = buf_end;????}????else????{?? /* 得到文件名 */????????file = strrchr(host_end, '/');????????if (file && (file + 1) != buf_end)????????????strcpy(file_name, file + 1);????}????if (colon) /* 得到端口號 */????{????????colon++;????????length = host_end - colon;????????memcpy(port_buf, colon, length);????????port_buf[length] = 0;????????*port = atoi(port_buf);????????host_end = colon - 1;????}????/* 得到主機信息 */????length = host_end - begin;????memcpy(host, begin, length);????host[length] = 0;}int main(int argc, char **argv){????WSADATA wsa_data;????SOCKET? http_sock = 0;???????? /* socket 句柄 */????struct sockaddr_in serv_addr;? /* 服務器地址 */????struct hostent *host_ent;?????????int result = 0, send_len;????char data_buf[HTTP_BUF_SIZE];????char host[HTTP_HOST_LEN] = "127.0.0.1";????unsigned short port = HTTP_DEF_PORT;????unsigned long addr;????char file_name[HTTP_HOST_LEN] = "index.html";????char file_nameforsave[HTTP_HOST_LEN] = "index1.html";????FILE *file_web;????if (argc != 2)????{????????printf("[Web] input : %s http://www.test.com[:8080]/index.html", argv[0]);????????return -1;????}????http_parse_request_url(argv[1], host, &port, file_name);????WSAStartup(MAKEWORD(2,0), &wsa_data); /* 初始化 WinSock 資源 */????addr = inet_addr(host);????if (addr == INADDR_NONE)????{????????host_ent = gethostbyname(host);????????if (!host_ent)????????{????????????printf("[Web] invalid host\n");????????????return -1;????????}?????????????????memcpy(&addr, host_ent->h_addr_list[0], host_ent->h_length);????}????/* 服務器地址 */????serv_addr.sin_family = AF_INET;????serv_addr.sin_port = htons(port);????serv_addr.sin_addr.s_addr = addr;????http_sock = socket(AF_INET, SOCK_STREAM, 0); /* 創建 socket */????result = connect(http_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));????if (result == SOCKET_ERROR) /* 連接失敗 */????{????????closesocket(http_sock);????????printf("[Web] fail to connect, error = %d\n", WSAGetLastError());????????return -1; ????}????/* 發送 HTTP 請求 */????send_len = sprintf(data_buf, http_req_hdr_tmpl, argv[1], host, port);????result = send(http_sock, data_buf, send_len, 0);????if (result == SOCKET_ERROR) /* 發送失敗 */????{????????printf("[Web] fail to send, error = %d\n", WSAGetLastError());????????return -1; ????}????file_web = fopen(file_nameforsave, "a+");?????????do /* 接收響應并保存到文件中 */????{????????result = recv(http_sock, data_buf, HTTP_BUF_SIZE, 0);????????if (result > 0)????????{????????????fwrite(data_buf, 1, result, file_web);????????????/* 在屏幕上輸出 */????????????data_buf[result] = 0;????????????printf("%s", data_buf);????????}????} while(result > 0);????fclose(file_web);????closesocket(http_sock);????WSACleanup();????return 0;}

?

?首先在vs2010中的,添加一個VC命令行程序,把上面的程序直接放到主程序對應的cpp文件中,然后編譯即可。

?

再貼上服務端的程序:

?

/*************************************************************************?* ?* Copyright (c) 2012-2013 by xuwm All Rights Reserved?*?* FILENAME:? WebSrv.c?*?* PURPOSE :? HTTP 服務器程序, 向客戶端提供請求的文件內容.?*? ?* AUTHOR? :? 許文敏?* ?**************************************************************************/#include "stdafx.h"#include <stdio.h>#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")? /* WinSock使用的庫函數 *//* 定義常量 */#define HTTP_DEF_PORT??????? 80???? /* 連接的缺省端口 */#define HTTP_BUF_SIZE????? 1024???? /* 緩沖區的大小 */#define HTTP_FILENAME_LEN?? 256???? /* 文件名長度 *//* 定義文件類型對應的 Content-Type */struct doc_type{????char *suffix; /* 文件后綴 */????char *type;?? /* Content-Type */};struct doc_type file_type[] = {????{"html",??? "text/html"? },????{"gif",???? "image/gif"? },????{"jpeg",??? "image/jpeg" },????{ NULL,????? NULL??????? }};char *http_res_hdr_tmpl = "HTTP/1.1 200 OK\r\nServer: Huiyong's Server <0.1>\r\n"????"Accept-Ranges: bytes\r\nContent-Length: %d\r\nConnection: close\r\n"????"Content-Type: %s\r\n\r\n";/**************************************************************************?*?* 函數功能: 根據文件后綴查找對應的 Content-Type.?*?* 參數說明: [IN] suffix, 文件名后綴;?*?* 返 回 值: 成功返回文件對應的 Content-Type, 失敗返回 NULL.?*?**************************************************************************/char *http_get_type_by_suffix(const char *suffix){????struct doc_type *type;????for (type = file_type; type->suffix; type++)????{????????if (strcmp(type->suffix, suffix) == 0)????????????return type->type;????}????return NULL;}/**************************************************************************?*?* 函數功能: 解析請求行, 得到文件名及其后綴. 請求行格式:?*?????????? [GET http://www.baidu.com:8080/index.html HTTP/1.1]?*?* 參數說明: [IN]? buf, 字符串指針數組;?*?????????? [IN]? buflen, buf 的長度;?*?????????? [OUT] file_name, 文件名;?*?????????? [OUT] suffix, 文件名后綴;?*?* 返 回 值: void.?*?**************************************************************************/void http_parse_request_cmd(char *buf, int buflen, char *file_name, char *suffix){????int length = 0;????char *begin, *end, *bias;????/* 查找 URL 的開始位置 */????begin = strchr(buf, ' ');????begin += 1;?????????????/* 查找 URL 的結束位置 */????end = strchr(begin, ' ');????*end = 0;????bias = strrchr(begin, '/');????length = end - bias;????/* 找到文件名的開始位置 */????if ((*bias == '/') || (*bias == '\\'))????{????????bias++;????????length--;????}????/* 得到文件名 */????if (length > 0)????{????????memcpy(file_name, bias, length);????????file_name[length] = 0;????????begin = strchr(file_name, '.');????????if (begin)????????????strcpy(suffix, begin + 1);????}}/**************************************************************************?*?* 函數功能: 向客戶端發送 HTTP 響應.?*?* 參數說明: [IN]? buf, 字符串指針數組;?*?????????? [IN]? buf_len, buf 的長度;?*?* 返 回 值: 成功返回非0, 失敗返回0.?*?**************************************************************************/int http_send_response(SOCKET soc, char *buf, int buf_len){????int read_len, file_len, hdr_len, send_len;????char *type;????char read_buf[HTTP_BUF_SIZE];????char http_header[HTTP_BUF_SIZE];????char file_name[HTTP_FILENAME_LEN] = "index.html", suffix[16] = "html";????FILE *res_file;????/* 得到文件名和后綴 */????http_parse_request_cmd(buf, buf_len, file_name, suffix);????res_file = fopen(file_name, "rb+"); /* 用二進制格式打開文件 */????if (res_file == NULL)????{????????printf("[Web] The file [%s] is not existed\n", file_name);????????return 0;????}????fseek(res_file, 0, SEEK_END);????file_len = ftell(res_file);????fseek(res_file, 0, SEEK_SET);?????????type = http_get_type_by_suffix(suffix); /* 文件對應的 Content-Type */????if (type == NULL)????{????????printf("[Web] There is not the related content type\n");????????return 0;????}????/* 構造 HTTP 首部,并發送 */????hdr_len = sprintf(http_header, http_res_hdr_tmpl, file_len, type);????send_len = send(soc, http_header, hdr_len, 0);????//send_len=1;????if (send_len == SOCKET_ERROR)????{????????fclose(res_file);????????printf("[Web] Fail to send, error = %d\n", WSAGetLastError());????????return 0;????}????do /* 發送文件, HTTP 的消息體 */????{????????read_len = fread(read_buf, sizeof(char), HTTP_BUF_SIZE, res_file);????????if (read_len > 0)????????{????????????send_len = send(soc, read_buf, read_len, 0);????????????file_len -= read_len;????????}????} while ((read_len > 0) && (file_len > 0));????fclose(res_file);?????????return 1;}int main(int argc, char **argv){????WSADATA wsa_data;????SOCKET? srv_soc = 0, acpt_soc;? /* socket 句柄 */????struct sockaddr_in serv_addr;?? /* 服務器地址? */????struct sockaddr_in from_addr;?? /* 客戶端地址? */????char recv_buf[HTTP_BUF_SIZE];????unsigned short port = HTTP_DEF_PORT;????int from_len = sizeof(from_addr);????int result = 0, recv_len;????if (argc == 2) /* 端口號 */????????port = atoi(argv[1]);????WSAStartup(MAKEWORD(2,0), &wsa_data); /* 初始化 WinSock 資源 */?????????srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 創建 socket */????if (srv_soc == INVALID_SOCKET)????{????????printf("[Web] socket() Fails, error = %d\n", WSAGetLastError());????????return -1; ????}?????????/* 服務器地址 */????serv_addr.sin_family = AF_INET;????serv_addr.sin_port = htons(port);????serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);????result = bind(srv_soc, (struct sockaddr *) &serv_addr, sizeof(serv_addr));????if (result == SOCKET_ERROR) /* 綁定失敗 */????{????????closesocket(srv_soc);????????printf("[Web] Fail to bind, error = %d\n", WSAGetLastError());????????return -1; ????}????result = listen(srv_soc, SOMAXCONN);????printf("[Web] The server is running ... ...\n");????while (1)????{????????acpt_soc = accept(srv_soc, (struct sockaddr *) &from_addr, &from_len);????????if (acpt_soc == INVALID_SOCKET) /* 接受失敗 */????????{????????????printf("[Web] Fail to accept, error = %d\n", WSAGetLastError());????????????break; ????????}????????printf("[Web] Accepted address:[%s], port:[%d]\n", ????????????inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));????????recv_len = recv(acpt_soc, recv_buf, HTTP_BUF_SIZE, 0);????????if (recv_len == SOCKET_ERROR) /* 接收失敗 */????????{????????????closesocket(acpt_soc);????????????printf("[Web] Fail to recv, error = %d\n", WSAGetLastError());????????????break; ????????}????????recv_buf[recv_len] = 0;????????/* 向客戶端發送響應數據 */????????result = http_send_response(acpt_soc, recv_buf, recv_len);????????closesocket(acpt_soc);????}?????????closesocket(srv_soc);????WSACleanup();????printf("[Web] The server is stopped.\n");????return 0;}

?這個也跟客戶端程序一樣,打開VS2010,新建一個VC命令行程序,COPY上面的代碼,直接放到主程序的CPP文件中,編譯即可。

運行代碼如下:

1.先運行服務端程序,綁定端口,然后開啟監聽? 在CMD里先切換到exe的目錄,然后 輸入 服務端程序名.exe 9000,此處服務端程序名換成對應的程序名稱.后面的9000端口號,也可以換成別的。

?2. 再運行客戶羰程序,同上面一樣,切換到exe?的目錄,然后輸入 客戶端程序名.exe http://127.0.0.1:9000/index.html,? 此處客戶端程序名換成對應的程序名稱,后面的http://127.0.0.1:9000/index.html,代表請求的網頁路徑。

?3. 在服務器的exe目錄下,應創建一個index.html文件,里面可以輸入一個正規的html文件。

以上只是學習網絡編程的一點小體會,盡當以后溫故:)

總結

以上是生活随笔為你收集整理的C语言实现的一个简单的HTTP程序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。