常见web服务器模型集合

来源:互联网 发布:php get 加密 编辑:程序博客网 时间:2024/05/17 15:58

一)采用多进程模式的web服务器

//=============================================================// 文件名称:web.c// 功能描述:HTTP Server// 维护记录:2011-11-10     V1.0// 维护成员: tianmo//=============================================================#include <stdio.h>#include <stdlib.h>#include <string.h> // bzero#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h> // inet_ntop#include <pthread.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>//=============================================================// 语法格式:    void main(void)// 实现功能:    主函数,建立一个HTTP Server// 入口参数:    无// 出口参数:    无//=============================================================int main(int argc, char *argv[]){    int sockfd;                            // 套接字    pid_t pid;                          //进程ID    struct sockaddr_in servAddr;        // 服务器地址结构体    struct sockaddr_in cliAddr;            // 用于保存客户端地址    char cliIP[INET_ADDRSTRLEN];        // 用于保存客户端IP地址    unsigned short port = 80;            // 监听端口    char head[]="HTTP/1.1 200 OK\r\n"\                 "Content-Type: text/html\r\n"\                "\r\n";    char err[]="HTTP/1.1 404 Not Found\r\n"\  "Content-Type: text/html\r\n"\      "\r\n"   \"<HTML><BODY>File not found</BODY></HTML>";        size_t cliAddrLen = sizeof(cliAddr); //计算客户端的地址大小    if(argc > 1)                        // 由参数接收端口    {        port = atoi(argv[1]);    }   printf("TCP Server Started at port %d!\n", port);    sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字                                       if(sockfd < 0)    {        perror("Invalid socket");        exit(1);    }    memset(&servAddr,0,sizeof(servAddr));// 初始化服务器地址    servAddr.sin_family = AF_INET;    servAddr.sin_port = htons(port);    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);    printf("Binding server to port %d\n", port);    if(bind(sockfd, (struct sockaddr*)&servAddr, sizeof(struct sockaddr)) != 0) //bind绑定套接字    {        close(sockfd);        perror("binding err!");        exit(1);    }    if(listen(sockfd, 1) != 0)//listen监听套接字    {        close(sockfd);        perror("listen err!");        exit(1);    }    printf("waiting client ...\n");    while(1)    {        int connfd = accept(sockfd, (struct sockaddr*)&cliAddr, &cliAddrLen);//等待服务器访问        printf("the connfd = *%d*\n",connfd);        inet_ntop(AF_INET, &cliAddr.sin_addr.s_addr, cliIP, INET_ADDRSTRLEN);        printf("client ip = %s\n", cliIP);        pid = fork();   //创建进程        if(pid == 0)        {            close(sockfd);                          //子进程中关闭主套接字            char recvbuf[1024]="";                    // 接收缓冲区           char filename[100];            int openfd;            char filebuf[1024];            read(connfd,recvbuf,1024);//从套接字中读取浏览器发送过来的数据.            sscanf(recvbuf,"GET /%[^ ]",filename);    //获取要浏览器请求的文件            printf("filename = *%s*\n",filename);           openfd = open(filename,O_RDONLY);        //打开浏览器请求的文件            if(openfd == -1)            {                printf("the file open error!\n");                write(connfd,err,strlen(err));    //文件打开失败发送错误提示            }            else            {                printf("the file open successful!\n");                //注意这里是用strlen(head),而不是sizeof(),用sizeof将会导致图片打不开                send(connfd,head,strlen(head),0);    //向浏览器发送请求OK的消息               int readflag = 0;                //将打开的文件中的数据依次的发送给浏览器                while((readflag=read(openfd,filebuf,sizeof(filebuf))) > 0)                {                    printf("readflag = *%d*\n",readflag);                    send(connfd,filebuf,readflag,0);//这里的发送数据大小为readflag,注意                }            }            close(connfd);//本次请求结束后关闭套接字            exit(0);//退出进程        }        else        {            close(connfd);//主进程要关闭子进程中用到的套接字,不然再次有请求时,会导致网页始终打不开.        }    }    close(sockfd);    return 0;}
//http://wenku.baidu.com/view/ddc50e39580216fc700afd4d.html/*================================================================purpose:* Fork 模型TCP并发服务器demoNotes:* 采用TCP短连接,服务器将接收到从不同客户端传来的消息并打印到终端* 编译:gcc fork.c -0 forkAuthor:* tianmoDate:* 10th Feb 2012Updates:*================================================================*/#include <netinet/in.h> //for sockaddr_in#include <sys/types.h>  //for socket#include <stdio.h> //for printf#include <stdlib.h> //for exit#include <string.h> //for bzero#include <unistd.h> // for fork#include <sys/signal.h> // for signal#include <sys/wait.h> // for wait#define HELLO_WORLD_SERVER_PORT 8888#define LENGTH_OF_LISTEN_QUEUE 20#define BUFFER_SIZE 1024void reaper(int sig){int status;//调用wait3读取子进程的返回值,使zombie状态的子进程彻底释放while(wait3(&status,WNOHANG,(struct rusage *)0) >= 0);}int main(){//设置一个socket地址结构server_addr,代表服务器internet地址,端口struct sockaddr_in server_addr;bzero(&server_addr,sizeof(server_addr));//把一段内存中区的全部内容设置为0server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htons(INADDR_ANY);server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);//创建用于internet的流协议(TCP)socket,用server_socket代表服务器socketint server_socket = socket(AF_INET,SOCK_STREAM,0);if(server_socket < 0){printf(Create Socket Failed.");exit(1);}//把socket和socket地址结构联系起来if(bind(server_socket,(struct sockaddr *)&server_addr,sizeof(server_addr))){printf("Server Bind Port : %d\n",HELLO_WORLD_SERVER_PORT);exit(1);}//server_socket用于监听if(listen(server_socket,LENGTH_OF_LISTEN_QUEUE)){printf("Server Listen Failed!");exit(1);}//通知操作系统,当收到子进程的退出信号(SIGCHLD),执行reaper函数,释放zombie状态的进程(void)signal(SIGCHLD,reaper);while(1)//服务器端需要一直运行{//定义客户端的socket地址结构client_addrstruct sockaddr_in client_addr;socklen_t length = sizeof(client_addr);int new_server_socket;//接受一个到server_socket代表的socket的一个连接//如果没有连接请求,就等待到有连接请求--这是accept函数的特性//accept函数返回一个新的socket,这个socket(new_server_socket)用于同连接到的客户通信//new_server_socket代表了服务器和客户端之间的一个通道//accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中new_server_socket = accept(server_socket,(struct sockaddr *)&client_addr,&length);if(new_server_socket < 0){printf("Server Accept Failed!\n");break;}int child_process_pid = fork();//fork()后,子进程是主进程的拷贝//在主进程和子进程中的区别是fork()的返回值不同 if(0 == child_process_pid)//如果当前进程是子进程,就执行与客户端的交互{close(server_socket);//子进程中不需要被复制过来的server_socketchar buffer[BUFFER_SIZE];bzero(buffer,BUFFER_SIZE * sizeof(char));strcpy(buffer,"Hello world!从服务器来!");strcat(buffer,"\n");//C语言字符串连接//发送buffer中的字符串倒new_server_socket,实际是给客户端send(new_server_socket,buff,BUFFER_SIZE,0);bzero(buffer,BUFFER_SIZE);//接收客户端发送过来的信息到buffer中length = recv(new_server_socket,buffer,BUFFER_SIZE,0);if(length < 0){printf("Server Receive Data Failed!\n");exit(1);}printf("\n%s",buffer);//关闭与客户端的连接close(new_server_socket);//TCP短连接exit(0);}else if(child_process_pid > 0)//如果当前进程是主进程close(new_server_socket);//主进程中不需要用于同客户端交互的new_server_socket}//关闭监听用的socketclose(server_socket);return 0;}
二)文件传输服务器和客户端程序

//////////////////////////////////////////////////////////////////////////////////////// file_server.c 文件传输顺序服务器示例////////////////////////////////////////////////////////////////////////////////////////本文件是服务器的代码#include <netinet/in.h>    // for sockaddr_in#include <sys/types.h>    // for socket#include <sys/socket.h>    // for socket#include <stdio.h>        // for printf#include <stdlib.h>        // for exit#include <string.h>        // for bzero/*#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>*/#define HELLO_WORLD_SERVER_PORT    6666 #define LENGTH_OF_LISTEN_QUEUE 20#define BUFFER_SIZE 1024#define FILE_NAME_MAX_SIZE 512int main(int argc, char **argv){    //设置一个socket地址结构server_addr,代表服务器internet地址, 端口    struct sockaddr_in server_addr;    bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0    server_addr.sin_family = AF_INET;    server_addr.sin_addr.s_addr = htons(INADDR_ANY);    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);    //创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket    int server_socket = socket(PF_INET,SOCK_STREAM,0);    if( server_socket < 0)    {        printf("Create Socket Failed!");        exit(1);    }        //把socket和socket地址结构联系起来    if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))    {        printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT);         exit(1);    }        //server_socket用于监听    if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )    {        printf("Server Listen Failed!");         exit(1);    }    while (1) //服务器端要一直运行    {        //定义客户端的socket地址结构client_addr        struct sockaddr_in client_addr;        socklen_t length = sizeof(client_addr);        //接受一个到server_socket代表的socket的一个连接        //如果没有连接请求,就等待到有连接请求--这是accept函数的特性        //accept函数返回一个新的socket,这个socket(new_server_socket)用于同连接到的客户的通信        //new_server_socket代表了服务器和客户端之间的一个通信通道        //accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中        int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);        if ( new_server_socket < 0)        {            printf("Server Accept Failed!\n");            break;        }                char buffer[BUFFER_SIZE];        bzero(buffer, BUFFER_SIZE);        length = recv(new_server_socket,buffer,BUFFER_SIZE,0);        if (length < 0)        {            printf("Server Recieve Data Failed!\n");            break;        }        char file_name[FILE_NAME_MAX_SIZE+1];        bzero(file_name, FILE_NAME_MAX_SIZE+1);        strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));//        int fp = open(file_name, O_RDONLY);//        if( fp < 0 )        FILE * fp = fopen(file_name,"r");        if(NULL == fp )        {            printf("File:\t%s Not Found\n", file_name);        }        else        {            bzero(buffer, BUFFER_SIZE);            int file_block_length = 0;//            while( (file_block_length = read(fp,buffer,BUFFER_SIZE))>0)            while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)            {                printf("file_block_length = %d\n",file_block_length);                //发送buffer中的字符串到new_server_socket,实际是给客户端                if(send(new_server_socket,buffer,file_block_length,0)<0)                {                    printf("Send File:\t%s Failed\n", file_name);                    break;                }                bzero(buffer, BUFFER_SIZE);            }//            close(fp);            fclose(fp);            printf("File:\t%s Transfer Finished\n",file_name);        }        //关闭与客户端的连接        close(new_server_socket);    }    //关闭监听用的socket    close(server_socket);    return 0;}
//////////////////////////////////////////////////////////////////////////////////////// file_client.c 文件传输客户端程序示例////////////////////////////////////////////////////////////////////////////////////////本文件是客户机的代码#include <netinet/in.h>    // for sockaddr_in#include <sys/types.h>    // for socket#include <sys/socket.h>    // for socket#include <stdio.h>        // for printf#include <stdlib.h>        // for exit#include <string.h>        // for bzero/*#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>*/#define HELLO_WORLD_SERVER_PORT    6666 #define BUFFER_SIZE 1024#define FILE_NAME_MAX_SIZE 512int main(int argc, char **argv){    if (argc != 2)    {        printf("Usage: ./%s ServerIPAddress\n",argv[0]);        exit(1);    }    //设置一个socket地址结构client_addr,代表客户机internet地址, 端口    struct sockaddr_in client_addr;    bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0    client_addr.sin_family = AF_INET;    //internet协议族    client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址    client_addr.sin_port = htons(0);    //0表示让系统自动分配一个空闲端口    //创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket    int client_socket = socket(AF_INET,SOCK_STREAM,0);    if( client_socket < 0)    {        printf("Create Socket Failed!\n");        exit(1);    }    //把客户机的socket和客户机的socket地址结构联系起来    if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))    {        printf("Client Bind Port Failed!\n");         exit(1);    }    //设置一个socket地址结构server_addr,代表服务器的internet地址, 端口    struct sockaddr_in server_addr;    bzero(&server_addr,sizeof(server_addr));    server_addr.sin_family = AF_INET;    if(inet_aton(argv[1],&server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数    {        printf("Server IP Address Error!\n");        exit(1);    }    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);    socklen_t server_addr_length = sizeof(server_addr);    //向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接    if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0)    {        printf("Can Not Connect To %s!\n",argv[1]);        exit(1);    }    char file_name[FILE_NAME_MAX_SIZE+1];    bzero(file_name, FILE_NAME_MAX_SIZE+1);    printf("Please Input File Name On Server:\t");    scanf("%s", file_name);        char buffer[BUFFER_SIZE];    bzero(buffer,BUFFER_SIZE);    strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));    //向服务器发送buffer中的数据    send(client_socket,buffer,BUFFER_SIZE,0);//    int fp = open(file_name, O_WRONLY|O_CREAT);//    if( fp < 0 )    FILE * fp = fopen(file_name,"w");    if(NULL == fp )    {        printf("File:\t%s Can Not Open To Write\n", file_name);        exit(1);    }        //从服务器接收数据到buffer中    bzero(buffer,BUFFER_SIZE);    int length = 0;    while( length = recv(client_socket,buffer,BUFFER_SIZE,0))    {        if(length < 0)        {            printf("Recieve Data From Server %s Failed!\n", argv[1]);            break;        }//        int write_length = write(fp, buffer,length);        int write_length = fwrite(buffer,sizeof(char),length,fp);        if (write_length<length)        {            printf("File:\t%s Write Failed\n", file_name);            break;        }        bzero(buffer,BUFFER_SIZE);        }    printf("Recieve File:\t %s From Server[%s] Finished\n",file_name, argv[1]);        fclose(fp);    //关闭socket    close(client_socket);    return 0;}
使用方法:

服务器端程序的编译:gcc -o file_server file_server.c
客户端程序的编译:gcc -o file_client file_client.c 
服务器程序和客户端程应当分别运行在2台计算机上.
服务器端程序的运行,在一个计算机的终端执行:./file_server
客户端程序的运行,在另一个计算机的终端中执行:./file_client 

运行服务器程序的计算机的IP地址,根据提示输入要传输的服务器上的文件,该文件在服务器的运行目录上,在实际编程和测试中,可以用2个终端代替2个计算机,这样就可以在一台计算机上测试网络程序。

服务器端程序的运行,在一个终端执行:./file_server,客户端程序的运行;在另一个终端中执行:./file_client 127.0.0.1

说明: 任何计算机都可以通过127.0.0.1访问自己. 也可以用计算机的实际IP地址代替127.0.0.1


原创粉丝点击