草庐IT

自己写的功能简单的 http server 文件下载服务器 http服务器

QMCY_jason 2024-01-01 原文

最近在项目中遇到过 通过ssh登录到某台机器A ,然后 又从A机器上ssh到机器B  而B机器是没有外网功能,这个时候如果想从B机器上传文件到A机器上就很不好办了  由于B机器没有外网 很多工具软件都没有  原来是是用python 起的http服务器 但是B机器没有安装python

于是就参照之前的项目经历写了一个简单的http server服务端 ,编译之后放在B机器上

然后在A机器上就可以通过wget命令 把文件下载下来了 

运行环境ubuntu 18.04  依赖于libevent库 

运行方式:

下载方式:

 程序同级目录需要有个download目录 程序里面写死了 是这个download目录 把需要下载的文件放到download目录即可

临时用可以了 解决了不能从B机器上下载文件到A机器上的问题 

下面直接贴源码:

#include"QMCY_HttpServer.h"


#include <future>



#define HTTP_PORT	8081
	//#define HTTP_IP	"0.0.0.0"
	
#define BUF_MAX 1024*16
#define CHANNEL_LIST_SIZE	1024*20
	
	char g_get_buf[CHANNEL_LIST_SIZE] = {0};
	char g_log_file_name[256]="123";

QMCY_OSD* g_pHandle =  NULL;




void QMCY_SendResponse(HTTP_REQ *req,const char* content)
{
	struct evbuffer *retbuff = NULL;
	retbuff = evbuffer_new();	
	if(retbuff == NULL)
	{
		printf("ret buff is NULL \n");
		//QMCY_LOG(HT_LOG_WARN,"QMCY_SendResponse get memory failed\n");
		return;
	}	
	evbuffer_add_printf(retbuff,content);
	evhttp_send_reply(req,HTTP_OK,"Client",retbuff);
	evbuffer_free(retbuff);	
}



void QMCY_PostHandler(HTTP_REQ *req,void *arg)
{
	char *buf = NULL;
	int valid_channels = 0;
	QMCY_OSD *pHandle =(QMCY_OSD*)arg;

	size_t post_size = 0;

	MSG_INFO msg;
	memset(&msg, 0, sizeof(msg));
	
	post_size = evbuffer_get_length(req->input_buffer);
	if (post_size == 0)
	{
		printf("QMCY post msg is empty!\n");
		return;
	}

	buf = (char*)malloc(post_size+1);
	if(buf == NULL)
	{
		return;
	}
	memset(buf,0,post_size+1);
	const char *uri = evhttp_request_get_uri(req);	

	size_t copy_len = post_size > BUF_MAX ? BUF_MAX : post_size;
	memcpy(buf, evbuffer_pullup(req->input_buffer,-1), copy_len);


	evhttp_add_header(evhttp_request_get_output_headers(req),
			"Content-Type", "application/json");


	QMCY_SendResponse(req,"{\"msg\":\"Success\", \"code\":200}");

	if(strcmp(uri,POST_URI_SET_LED) == 0)
	{

	}
	else if(strcmp(uri,POST_URI_UPDATE_LED) == 0)
	{


		
	}	
	
	else if(strcmp(uri,POST_URI_STOP) == 0)
	{

	}

	else
	{

		printf("Post is:[%s]\n",buf);
	
		//QMCY_LOG(HT_LOG_WARN,"Undefined post method:%s\n",uri);
	}

	free(buf);

}








void QMCY_GetHandler(HTTP_REQ *req,void *arg)
{
	char *buf = g_get_buf;

	QMCY_OSD *pHandle = (QMCY_OSD *)arg;

	char file_buf[1024] = { 0 };

	if(pHandle == NULL)
	{
		return;
	}
	
	if(!req )
	{
		return ;
	}


	memset(buf,0,CHANNEL_LIST_SIZE);
	
	const char *uri = evhttp_request_get_uri(req);	

	//evhttp_set_default_content_type

	evhttp_add_header(evhttp_request_get_output_headers(req),
			"Content-Type", "application/json");


	if(strncmp(uri,"/download",strlen("/download")) == 0)
	{
		string file_name = ".";
		file_name.append(uri);

		if(file_name == "./download" || file_name == "./download/")
		{
			printf("file does not exist\n");
			evhttp_send_reply(req, HTTP_NOTFOUND, "File not found", 0);//返回未找到
			return;
		}

		long filesize = 0;

		printf("Request file is[%s]\n",file_name.c_str());

		//log_print(HT_LOG_INFO,"%s Request file is[%s]\n",__FUNCTION__,file_name.c_str());					

		//读取html文件返回正文
		FILE *fp = fopen(file_name.c_str(), "rb");
		if (!fp){
			printf("file does not exist\n");
			evhttp_send_reply(req, HTTP_NOTFOUND, "File not found", 0);//返回未找到
			//这里可以自定义未找到页面
			return;
		}

		fseek(fp, 0, SEEK_END);
		filesize = ftell(fp);
		fseek(fp,0,SEEK_SET);

		time_t timep;
		time(&timep);
		char s[50];
		sprintf(s, ctime(&timep));
  		std::string strDate = std::string(s, s + (strlen(s) - 1));
		char FileSize[10] = {0};

		snprintf(FileSize, sizeof(FileSize), "%d", filesize);

		evhttp_add_header(evhttp_request_get_output_headers(req), "Server", "QMCY");
		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "application/octet-stream; charset=utf-8");
		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Disposition", file_name.c_str());
		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", FileSize);
		evhttp_add_header(evhttp_request_get_output_headers(req), "Date", strDate.c_str());
		evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");

		evbuffer *outbuf = evhttp_request_get_output_buffer(req); //返回的body
		while (true){
			int len = fread(file_buf, 1, sizeof(file_buf), fp); //不断读取,解决文件过大一次性读不完的问题
			if (len <= 0)break;
			evbuffer_add(outbuf, file_buf, len);
		}
		
		fclose(fp);
		printf("Read complete send to client\n");

		//log_print(HT_LOG_INFO,"%s Read complete send to client [%s]\n",__FUNCTION__,file_name.c_str());					

		evhttp_send_reply(req, HTTP_OK, "Client", outbuf);

		QMCY_SendResponse(req,"Download finished!!!");
		return;
	}
	else if(strcmp(uri,GET_URI_LOGNAME) == 0)
	{

	}	
	else if((strcmp(uri,GET_URI_CHANNEL_LIST) == 0))
	{
	}
	else if((strcmp(uri,GET_URI_TEST) == 0))
	{
		//QMCY_ParseAuthentication(NULL,pHandle);
	}	
	else
	{
		sprintf(buf,
			"{\r\n "
			"%s:%s" 		
			"\r\n}","Undefined command!!!",uri);

		//QMCY_LOG(HT_LOG_WARN,"Undefined GET method:%s\n",uri);

	}

	QMCY_SendResponse(req,buf);


	
}



void QMCY_HttpHandler(HTTP_REQ *req,void *arg)
{
	int method= 0;

	if(req == NULL)
	{
		return;
	}
	method = evhttp_request_get_command(req);
	
	if(method == EVHTTP_REQ_GET)
	{
		QMCY_GetHandler(req,arg);
	}
	if(method == EVHTTP_REQ_POST)
	{
		QMCY_PostHandler(req,arg);
	}

	return;

}


void QMCY_StopHttp()
{
	event_loopbreak();
}



void * QMCY_StartHttp(void *args)
{
	struct evhttp *http_server = NULL;
	short http_port = HTTP_PORT;
	const char *http_addr = HTTP_IP;

	QMCY_OSD *pHandle =reinterpret_cast<QMCY_OSD *>(args);
	
	http_port = pHandle->local_port;

#if defined(_WIN32) || defined(_WIN64)
	evthread_use_windows_threads();
#else
	evthread_use_pthreads();
#endif
	
	event_init();

	http_server = evhttp_start(http_addr,http_port);
	if(http_server == NULL)
	{
		printf("Http server start failed.\n");
		//QMCY_LOG(HT_LOG_FATAL,"Http server start failed\n");

		QMCY_Stop(pHandle);
		return NULL;
	}
	else
	{
		printf("Http server start at %s:%d.\n",pHandle->local_ip,pHandle->local_port);
		//QMCY_LOG(HT_LOG_INFO,"Http server start at %s:%d.\n",pHandle->device_ip,pHandle->device_port);
	}
	
	evhttp_set_timeout(http_server,5);
	//evhttp_set_cb(http_server, "/qmcy/upload", HttpUpFile, NULL);
	evhttp_set_gencb(http_server,QMCY_HttpHandler, args);

	event_dispatch();
	evhttp_free(http_server);
	printf("\n Http server exit.\n");
	//QMCY_LOG(HT_LOG_INFO,"Http server exit\n"); 
	return NULL;	
}







void handler(int signum)
{
    if(signum == SIGIO)
        printf("SIGIO   signal: %d\n", signum);
    else if(signum == SIGPIPE)
        printf("SIGPIPE   signal: %d\n", signum);
    else
	{
		QMCY_Stop(g_pHandle);
		printf("error\n");
	}
}


int QMCY_Start(QMCY_OSD *pHandle)
{

	pHandle->http_thread = std::thread(QMCY_StartHttp, pHandle);
	pHandle->run_flag.store(true);

	printf("QMCY OSD system successfully started\n");
	
	while(pHandle->run_flag.load())
	{
		sleep(1);
	}
 	cout << __FUNCTION__ << " exit" << endl;
	return 1;
	
}



void QMCY_Stop(QMCY_OSD *pHandle)
{
	pHandle->run_flag.store(false);

	
	QMCY_StopHttp();
	
	pHandle->http_thread.join();



}



int main(int argc,char *argv[])
{
	int ret = 0;
	int port = 8000;

	
	QMCY_OSD  handle ={0};

	g_pHandle = &handle;


	if(argc == 2)
	{
		port = atoi(argv[1]);
	}

	handle.local_port = port;


	signal(SIGPIPE, SIG_IGN);

	
	QMCY_Start(&handle);

	QMCY_Stop(&handle);

	printf("QMCY ------------------------> Exit normally \n");		
}

由于这个是从其他项目里面摘出来的 所以有很多额外的代码痕迹 略过即可 

更新了下 之前 必须程序同级目录有download目录才可以 现在去掉了这个限制

直接是程序运行当前目录即可:

运行如下:

 下载方式:

程序当前目录详情:

 

 

这样就和python的http方式一样了

python -m SimpleHTTPServer 8000

代码其实更简单 只需要把download那里注释掉就可以了

如下:

 

有关自己写的功能简单的 http server 文件下载服务器 http服务器的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  4. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  5. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  6. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  7. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  8. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  9. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

  10. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

随机推荐