C语言实现简单HTTP 服务器

开发平台:Microsoft Visual Studio Community 2019

#include <stdio.h>
#include <winsock2.h>
#include <string.h>
#include <io.h>

#pragma comment(lib, "ws2_32.lib")

/*
* 网络编程  包含头文件:  winsock2.h
*           引用库文件:  ws2_32.lib
*/


char rev_buffer[1024];	//接收信息缓冲区
char filePath[128];		//网页文件路径


/**
* 主要步骤:
* 1.初始化网络库
* 2.创建socket
* 3.绑定IP地址和端口号
* 4.监听连接
* 5.接收连接
* 6.处理连接请求
* 7.关闭连接,关闭网络库
**/


int main()
{

	//============================================================================
	//1.初始化网络库  WSA --> Windows Socket API
	//para1:指定socket版本  使用最新的2.2版本即可
	//para2:是一个传出参数

	int ret;
	WSADATA wsadata;

	ret = WSAStartup(MAKEWORD(2, 2), &wsadata);
	if (ret != 0)
	{
		printf("WSADATA启动失败\r\n");
		exit(-1);
	}
	else
	{
		printf("WSADATA启动成功\r\n");
	}

	//============================================================================
	//2.创建socket
	//para1:指定IP协议  AF_INET -> IPV4  AF_INET6 -> IPV6
	//para2:数据传输格式  常用的有两种:流式传输(TCP)  数据包传输(UDP)
	//para3:传输协议:

	SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (serverSocket == INVALID_SOCKET)
	{
		printf("创建serverSocket失败\r\n");
		exit(-1);
	}
	else
	{
		printf("创建serverSocket成功\r\n");
	}

	============================================================================
	//3.绑定IP地址和端口号(对于服务器是绑定,对于客户端是连接)
	//para1:  指定socket
	//para2:  IP地址和端口号
	//para3:  para2的长度

	SOCKADDR_IN serverAddr;
	serverAddr.sin_family = AF_INET;//必须和创建socket时一样
	serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;
	serverAddr.sin_port = htons(80);//此处涉及到大端存储和小端存储    一般计算机上都是小端的 网络上一般都是大端的  所以需要将本地字节序转为网络字节序

	ret = bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
	if (ret == SOCKET_ERROR)
	{
		printf("套接字绑定失败\r\n");
		exit(-1);
	}
	else
	{
		printf("套接字绑定成功\r\n");
	}

	//============================================================================
	//4.监听连接

	listen(serverSocket, 10);
	printf("服务器监听中......\r\n");

	//============================================================================
	//5.接收连接

	SOCKADDR clientAddr;
	int len_clientAddr = sizeof(clientAddr);

	while (1)
	{
		SOCKET clientSocket = accept(serverSocket, &clientAddr, &len_clientAddr);
		if (clientSocket == INVALID_SOCKET)
		{
			printf("建立客户端连接失败\r\n");
			exit(-1);
		}
		else
		{
			printf("成功建立客户端连接\r\n");
		}

		//6.处理连接请求
		//从clientSocket接受数据

		ret = recv(clientSocket, rev_buffer, sizeof(rev_buffer), 0);
		printf("The return of recv is:%d\r\n", ret);

		if (ret <= 0)
		{
			printf("接收来自客户端的数据失败\r\n");
			printf("重新进入等待连接状态......\r\n");
			closesocket(clientSocket);
			continue;
			//exit(-1);
		}
		else
		{
			printf("成功接收来自客户端的数据:\r\n");
			printf("%s\r\n", rev_buffer);
		}

		//给客户发送网页	后续可以根据具体请求,转向不同页面
		strcpy(filePath, "index.html");

		ret = access(filePath, 0);//0 代表判断文件是否存在  如果存在返回0 否则返回-1
		if (ret != 0)
		{
			//未找到文件
			char sendBuf[1024] = { 0 };

			sprintf(sendBuf, "HTTP/1.1 404 NOT FOUND\r\n");
			send(clientSocket, sendBuf, strlen(sendBuf), 0);

			sprintf(sendBuf, "Content-type:text/html\r\n");
			send(clientSocket, sendBuf, strlen(sendBuf), 0);

			sprintf(sendBuf, "\r\n");
			send(clientSocket, sendBuf, strlen(sendBuf), 0);


			sprintf(sendBuf, "找不到,滚!!!!\r\n");
			send(clientSocket, sendBuf, strlen(sendBuf), 0);
		}
		else
		{
			//找到相关网页文件
			FILE* fs = fopen(filePath, "r");
			if (fs == NULL)
			{
				printf("打开网页文件失败\r\n");
				exit(-1);
			}
			else
			{
				char dataBuf[1024] = { 0 };

				sprintf(dataBuf, "http/1.1 200 success\r\n");
				send(clientSocket, dataBuf, strlen(dataBuf), 0);

				sprintf(dataBuf, "content-type:text/html\r\n");
				send(clientSocket, dataBuf, strlen(dataBuf), 0);

				sprintf(dataBuf, "\r\n");
				send(clientSocket, dataBuf, strlen(dataBuf), 0);

				do
				{
					fgets(dataBuf, 1024, fs);
					send(clientSocket, dataBuf, strlen(dataBuf), 0);
				} while (!feof(fs));

				fclose(fs);
			}
		}
		closesocket(clientSocket);//发送完直接关闭  因为HTTP协议是无连接的
	}

	//7.关闭连接,清理网络库

	closesocket(serverSocket);
	WSACleanup();

	return 0;
}

  • 5
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值