记录:
非常简单的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__);
}
}
}