非常简单的WEB服务器

记录:
  非常简单的WEB处理程序,很多时候有新想法,可以用这个试验,没有安装和配置。这个就是监听一个端口,把连接重定向到另一个程序中,而这个程序就是新想法。
  JAVA的类库很多,很方便。尤其是不用安装、配置,很方便。


/*
——————————————————————————————————————————————————————————————————————————————

作用:
    这是最简单的类WEB服务程序,因为很多时候就为试验一个新想法,
懒得安装和配置那种复杂的WEB服务器端。这个最简单,无需维护,即想即用,非常方便。
    这个程序就是监听一个端口,收到连接后,启动另一个程序处理里面的内容。而被启动
的程序可以使用标准输入输出,按照课本中那样最简单的方法来接收、处理数据。这里是启动了一个JAVA程序,
因为JAVA的各种类库用起来真的很简单、方便。并且各种程序只要一个JDK就可以了,不用安装就能很方便运行。

作者:ZX

时间:贰零贰壹年肆月某日

——————————————————————————————————————————————————————————————————————————————
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<errno.h>
#include<fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/prctl.h>

/*
——————————————————————————————————————————————————————————————————————————————
*/

#define SERV_PORT 9000

extern int errno;

/*
——————————————————————————————————————————————————————————————————————————————
*/

int main()
{
	int listenfd = -1;

	if( setpgid(getpid() , getpid()) < 0 )
	{ // 设置进程组,方便管理。
		perror("错误:setpgid\n");
		exit(__LINE__);
	}

	signal(SIGCLD, SIG_IGN); /* 不处理子进程的结束信号 */

	{
		char name[32];
		prctl(PR_SET_NAME, (unsigned long)"ZX web");
		prctl(PR_GET_NAME, (unsigned long)name);
		printf("%s\n", name);
	}

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0)
	{
		perror("错误:socket\n");
		exit(__LINE__);
	}
	else
	{
		printf("socket()\r\n");
	}
	if (fcntl(listenfd, F_SETFD, FD_CLOEXEC) != 0)
	{
		 /*意为如果对描述符设置了FD_CLOEXEC,
		 **使用execl执行的程序里,此描述符被关闭,不能再使用它,
		 **但是在使用fork调用的子进程中,此描述符并不关闭,仍可使用。*/
		perror("错误:fcntl\n");
		exit(__LINE__);
	}
	else
	{
		printf("fcntl()\r\n");
	}

	{
		int yes = 1;
		if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0)
		{
			perror("错误:setsockopt\n");
			exit(__LINE__);
		}
		else
		{
			printf("setsockopt()\r\n");
		}
	}

	{
		struct sockaddr_in servaddr;
		bzero(&servaddr, sizeof(servaddr));
		servaddr.sin_family = AF_INET;
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);   //因为本机地址可以有很多种表示,htonl只是为了保险起见,可以去掉
		servaddr.sin_port = htons(SERV_PORT);

		if (bind(listenfd, (struct sockaddr*) & servaddr, sizeof(servaddr)) == 0)
		{
			printf("bind()\r\n");
		}
		else
		{
			perror("错误:bind\n");
			exit(__LINE__);
		}
	}

	if (listen(listenfd, 100) == 0)
	{
		/*
		* 监听端口,100表示侦听队列的长度。
		* 在进程正在处理一个连接请求的时候,可能还存在其它的连接请求。
		* 因为TCP连接是一个过程,所以可能存在一种半连接的状态,
		* 有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。
		* 如果这个情况出现了,服务器进程希望内核如何处理呢?
		* 内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接,
		* 但服务器进程还没有接手处理的连接(还没有调用accept函数的连接),
		* 这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。
		* 这个backlog告诉内核使用这个数值作为上限。
        */
		printf("listen()\n");
	}
	else
	{
		perror("错误:listen\n");
		exit(__LINE__);
	}

	while (1)
	{
		int connfd = -1;
		struct sockaddr_in cliaddr;
		socklen_t cliaddr_len;
		cliaddr_len = sizeof(cliaddr);
		connfd = accept(listenfd, (struct sockaddr*) & cliaddr, &cliaddr_len);   //如果得不到客户端发来的消息,将会被阻塞,一直等到消息到来
		if (connfd > 0)
		{
			int pid = -1;
			printf("accept()\r\n");
			
			pid = fork();
			if (pid < 0)
			{
				perror("错误:fork():create subprocess fail.\n");
				close(connfd);
			}
			else if (pid == 0)
			{
				printf("————子进程运行.\n");
				dup2(connfd, 0); // 重定向子进程的stdin、stdout
				dup2(connfd, 1); // 重定向子进程的stdin、stdout

				return execl("/usr/local/jdk/bin/java", "java", "-jar", "/opt/java/T200/data/httpUntitled2.jar", NULL);
			}
			else
			{
				printf("fork()\r\n");
				/* 传递给子进程后,关闭自己这边的socket文件。*/
				close(connfd);
				connfd = -1;
			}
		}
		else
		{
			perror("错误:accept\n");
			exit(__LINE__);
		}
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值