用 VC++ 和 Winsock 实现与 HTTP 服务器通话

用 VC++ 和 Winsock 实现与 HTTP 服务器通话 
作者:Ji Hong 


一、引 言
---- Windows Socket API是一套开放的、支持多种协议的Windows下的网络编程接口,它包 括一个标准的 Berkeley Socket功能调用的集合,以及为Windows所作的重要扩充。 Windows Socket经过不断完善并在众 多公司的全力支持下,已成为Windows网络编程 的事实上的标准。

---- 本 文 将 在VC++ 5.0 环 境 下 介 绍 一个基于 Winsock 的 HTTP 客户应用程序。 读者可以基于本例 同样的原理实现其他Internet常用协议(time, SMTP, POP3, Telnet, FTP 等)的客户应用程序。

二、一个简单的浏览器
---- 我将创建一个简单的浏览器,以说明如何通过Winsock基于HTTP协议实现HTTP 客户应 用程序。

---- 首先我将创建一个帮助函数 LogFile(),该函数把传递给它的字符串写到磁盘文件 中。然后再创建 本示例的核心函数 -- HttpClient() 。在这个核心函数中,我将通 过 Winsock 连接到 HTTP 服务器上 (本例中我将使用计算机世界日报 168.160.224.185)。当连接成功后,发送 Get 命令到 HTTP 服务器 去下载指定路径 上(/99/tips/)的文件。通过帮助函数 LogFile() 把下载的数据记录到本地磁盘文 件中。

char fname[MAXPATH];
void LogFile(char *p)
{
FILE *fp=fopen(fname,"a+");
fprintf(fp,"%s/n",p);
fclose(fp);
}

BOOL HttpClient(void)
{
WSADATA ws;
SOCKET s;
struct sockaddr_in addr;

int iResult;
long lResult;
char strSubAddr[100], strBuffer[100];

lResult = WSAStartup(0x0101,&ws);
s = socket(AF_INET,SOCK_STREAM,0);

addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.s_addr = inet_addr
("168.160.224.185"); // 计算机世界日报
iResult=connect(s,(struct sockaddr *)
&addr, sizeof(addr));
if(SOCKET_ERROR == iResult)
{
// 连接失败
WSACleanup();
return FALSE;
}
else {
// 连接成功
strcpy(strSubAddr, "GET /99/tips/ /r/n");
strcpy(fname, "index.htm");
iResult = send(s, strSubAddr,strlen(strSubAddr),0);

// 下载文件
do {
strset(strBuffer,' ');
iResult = recv(s,strBuffer,sizeof(strBuffer),0);
LogFile(strBuffer);
} while( iResult !=0 );
}

WSACleanup();
return TRUE;
}

三、测试
---- 打开Visual C++ 5.0, 用MFC创建基于对话框的工程Test, 并在对话框上放 置"Test" 按 钮, 然后添加测试代码。

Void CTestDlg::OnTest()
{
HttpClient();
}

---- 编译并运行该测试程序,在测试对话框中,单击 "Test" 按钮,

---- "http://www.computerworld.com.cn/99/tips/"的index.htm文件将被下载到本地。

四. 结 论
---- 这应该就是Netscape Navigator,Internet Explorer以及其他浏览器实现Internet访 问的基本代码了. 在这些浏览器中,其他百分之九十以上的代码主要用于HTML显示等 本地处理上。

---- 读者如果有兴趣,基于这些代码,再加入一些解释HTML命令的代码,就可以正确显示 所下载的HTML文件, 那也就是说将拥有自己版本的一个百分之百的浏览器了。何不一试 ?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 利用 winsock 编程实现简单 web 服务器的步骤如下: 1. 创建一个 socket,使用 TCP 协议。 2. 绑定 socket 到本地 IP 地址和端口号。 3. 监听 socket,等待客户端连接。 4. 接受客户端连接请求,创建一个新的 socket 与客户端通信。 5. 接收客户端发送的 HTTP 请求。 6. 解析 HTTP 请求,获取请求的文件名和请求方法。 7. 打开请求的文件,读取文件内容。 8. 构造 HTTP 响应,包括响应头和响应体。 9. 发送 HTTP 响应给客户端。 10. 关闭与客户端的连接,等待下一个客户端连接。 以上是利用 winsock 编程实现简单 web 服务器的基本步骤,具体实现还需要考虑一些细节问题,如并发处理、错误处理等。 ### 回答2: WinsockWindows sockets)是一种基于 Windows 操作系统的网络编程接口,可以方便地通过程序来实现网络通讯的功能。Web服务器就是一种基于 HTTP 协议的网络应用程序,可以接收来自客户端的请求信息,并返回响应信息。 在使用 Winsock 编程实现简单 web 服务器时,需要遵循以下步骤: 1. 创建套接字 使用 Winsock API 函数中的 socket() 函数创建一个套接字,该套接字需要绑定到一个 IP 地址和端口号。 2. 监听端口 调用 Winsock API 函数中的 bind() 函数将套接字绑定到 IP 地址和端口号,并调用 listen() 函数开始监听客户端请求。 3. 等待连接 使用 Winsock API 函数中的 accept() 函数等待客户端连接请求。当有客户端请求连接时,accept() 函数将返回一个新的套接字,服务器可以使用该套接字与客户端进行通讯。 4. 接收请求 使用 recv() 函数接收客户端传来的请求信息,该请求信息必须符合 HTTP 协议格式。 5. 处理请求 当服务器接收到请求信息后,需要进行解析和处理。根据请求中的 URL,可以确定客户端需要访问的资源,服务器可以根据需要读取相应的文件并将文件内容发送给客户端。当然,这个过程中还需要处理错误信息和异常情况。 6. 发送响应 当服务器处理完请求后,需要使用 send() 函数将响应信息发送给客户端。 以上就是使用 Winsock 编程实现简单 web 服务器的基本步骤,当然,在具体实现过程中,还需要考虑如何提高服务器的性能、处理多个客户端等问题。总之,在网络编程领域,Winsock 作为常用的编程接口,可以为程序员们的网络编程工作提供有力支持。 ### 回答3: Web 服务器是一项非常常见并广泛应用的网络技术,对于想要学习网络编程的开发者来说,掌握如何利用winsock编程实现简单的web服务器是非常有必要的。 一般地,web服务器程序主要由两个部分组成:HTTP请求处理和HTTP响应处理。通过利用winsock提供的API接口,可以实现这些处理部分。HTTP请求处理需要解析客户端的HTTP请求头,首先获取请求的网页文件路径信息,然后判断该文件是否存在,若文件存在,则读取文件数据;若文件不存在,则返回404状态码。HTTP响应处理则需要构建HTTP响应头,包括状态行、消息报头和实体内容,将下发给客户端。 以下是一些可能用到的winsock的API接口: 1. socket() 创建socket 2. bind() 绑定IP和端口号 3. listen() 监听连接请求 4. accept() 接受连接请求 5. recv() 接收数据 6. send() 发送数据 7. closesocket() 关闭socket连接 这里提供一个简单的Winsock编程实现HTTP协议的web服务器程序示例: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") // 链接 Winsock2 库 #define MAX_BUF_SIZE 1024 // 缓存区大小 int main() { WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); // 初始化 Winsock2 if (iResult != 0) { printf("WSAStartup failed! Error code: %d", iResult); return 1; } // 创建 socket SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listenSocket == INVALID_SOCKET) { printf("Creating socket failed! Error code: %d", WSAGetLastError()); return 1; } // 绑定 IP 地址和端口号 sockaddr_in sockAddr; sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); sockAddr.sin_port = htons(80); iResult = bind(listenSocket, (sockaddr*)&sockAddr, sizeof(sockAddr)); if (iResult == SOCKET_ERROR) { printf("Binding socket failed! Error code: %d", WSAGetLastError()); closesocket(listenSocket); return 1; } // 监听连接请求 iResult = listen(listenSocket, SOMAXCONN); if (iResult == SOCKET_ERROR) { printf("Listening socket failed! Error code: %d", WSAGetLastError()); closesocket(listenSocket); return 1; } char buf[MAX_BUF_SIZE]; // 缓存区 while (TRUE) { // 接受连接请求 SOCKADDR_IN addrClient; int iLength = sizeof(SOCKADDR_IN); SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&addrClient, &iLength); if (clientSocket == INVALID_SOCKET) { printf("Accepting socket failed! Error code: %d", WSAGetLastError()); closesocket(listenSocket); return 1; } // 接收数据 iResult = recv(clientSocket, buf, MAX_BUF_SIZE, NULL); if (iResult == SOCKET_ERROR) { printf("Receiving data failed! Error code: %d", WSAGetLastError()); closesocket(clientSocket); continue; } buf[iResult] = '\0'; // 让接收到的数据末尾为 \0 // HTTP 请求处理,这里解析了 HTTP 请求中 GET 命令 if (strncmp(buf, "GET", 3) == 0) { char* pPath = strchr(buf, '/'); char* pEnd = strchr(pPath, ' '); if (pEnd == NULL) { closesocket(clientSocket); continue; } *pEnd = '\0'; // 文件路径字符串最后以 \0 结束 char pathBuf[MAX_BUF_SIZE]; memset(pathBuf, '\0', MAX_BUF_SIZE); // 初始化 pathBuf // 处理 HTTP 请求中的文件路径信息 if (strcmp(pPath, "/") == 0) { sprintf(pathBuf, "./index.html"); // 指定默认主页为 index.html } else { sprintf(pathBuf, ".%s", pPath); } FILE* pFile = fopen(pathBuf, "rb"); if (pFile == NULL) { // 发送 HTTP 响应的消息报头数据 sprintf(buf, "HTTP/1.1 404 File Not Found\r\n"); send(clientSocket, buf, strlen(buf), NULL); sprintf(buf, "Content-Type:text/html\r\n\r\n"); send(clientSocket, buf, strlen(buf), NULL); // 发送 HTTP 响应的实体内容数据 sprintf(buf, "<html><body><h1>File Not Found</h1></body></html>"); send(clientSocket, buf, strlen(buf), NULL); } else { // 发送 HTTP 响应的消息报头数据 sprintf(buf, "HTTP/1.1 200 OK\r\n"); send(clientSocket, buf, strlen(buf), NULL); sprintf(buf, "Content-Type:text/html\r\n\r\n"); send(clientSocket, buf, strlen(buf), NULL); // 读取文件数据并发送 HTTP 响应的实体内容数据 int iReadLen = 0; do { iReadLen = fread(buf, 1, MAX_BUF_SIZE, pFile); send(clientSocket, buf, iReadLen, NULL); } while (iReadLen == MAX_BUF_SIZE); // 如果已达到文件尾则结束 while 循环 fclose(pFile); } } closesocket(clientSocket); // 关闭 socket 连接 } WSACleanup(); // 清理 Winsock2 return 0; } 以上示例程序是一个确死版本的web服务器,具有非常基本的功能,同时方便学习和实践。为了提高web服务器的性能和功能,可以学习更加多的winsock编程的知识和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ren20

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值