多进程架构设计

本文详细介绍了从单进程到多进程的网络服务架构设计,包括TCP通信基础、服务端实例程序设计、性能测试,以及如何通过多进程提高服务性能。在单进程服务的基础上,通过引入子进程处理业务逻辑,性能提升显著。最后,文章探讨了多进程网络服务的设计,实现了并发处理并进行了性能测试,验证了多进程架构的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多进程架构设计

 

第一篇 网络服务

    现实生活中,网络通信的例子很多,例如,我们用浏览器打开一个网页,这个浏览器程序就向服务器发送一个HTTP请求,服务器收到这个请求后,经一番内部的逻辑处理,就将结果(网页)返回给浏览器。这实质上是一个TCP通信过程,这里的浏览器是客户端,服务器是服务端。本篇将用实例来讲述TCP通信过程,主要是服务端的实现。

 

第一章 完全的单进程服务

一、TCP网络通信基础

TCP通信是网络通信中最常用的一种,开篇中提到的大名鼎鼎的HTTP协议就是建立在TCP之上的。为了简化网络通信编程,系统设计人员设计了一种叫做套接字(socket)的东西。下面就如何利用socket实现TCP网络通信编程。

TCP网络通信分为客户端和服务端。客户端编程过程如下:

1、 产生一个套接字-socket;

2、 连接到服务器-connect;

3、 往对方发送数据-send/write;

4、 接收数据-recv/read;

5、 关闭套接字-close;

服务端编程:

1、 产生一个套接字-socket;

2、 bind一个端口;

3、 listen这个端口;

4、 accept等待客户端连接;

5、 传送数据:write/read或send/recv;

6、 关闭套接字;

 

(以上所讲是socket的同步通信,这是最简单的TCP编程模式,我们就采纳这种模式。至于异步通信,需要使用select函数,在本篇中完全忽略掉。)

 

二、服务端实例程序设计

下面是我设计的一个完全单进程服务程序:

#include<unistd.h>

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<sys/stat.h>

#include<errno.h>

#include<stdarg.h>

#include<sys/resource.h>

#include<sys/socket.h>

 

#include<fxapi.h>

#include<appdef.h>

 

#defineLOG_FILE     "test1.log"

#defineBUF_SIZE     1024*4

static  int log_id = 0;

 

staticint BUSIService(const char * _info, char * _imsg_data, int _ilen, char **_omsg_data, int * _olen);

 

 

intfd_svr;

intfd_cli;

 

 

intmain(int argc, char ** argv)

{

    int   ret    = 0;

    int   len    = 0;

    unsigned int count = 0;

    struct sockaddr_in sa;

    char  * obuf = NULL;

    char  ibuf[BUF_SIZE];

    char  szTmp[128];

 

    fx_log(log_id, LOG_FILE, _FL_, "启动服务...");

    fd_svr = fx_server(NULL, 12345);

    if (fd_svr < 0)

    {

        fx_log(log_id, LOG_FILE, _FL_, "启动服务失败");

        exit(-1);

    }

 

    while(1)

    {

        fx_log(log_id, LOG_FILE, _FL_, "等待客户端连接...");

        memset(&sa, 0x00, sizeof(sa));

        fd_cli = fx_accept(fd_svr, &sa);

        if (fd_cli > 0)

        {

            count++;

        }

        else

        {

            fx_log(log_id, LOG_FILE, _FL_,"客户端连接失败");

            continue;

        }

 

        /* 输出客户端信息 */

        fx_log(log_id, LOG_FILE, _FL_, "客户端%u:%s:%d", count,inet_ntop(AF_INET, &sa.sin_addr, szTmp, sizeof(szTmp)),ntohs(sa.sin_port));

 

        /* 读取客户端请求信息 */

        ret = read(fd_cli, ibuf, BUF_SIZE);

        if (ret < 0)

        {

            fx_log(log_id, LOG_FILE, _FL_,"接收数据失败");

            close(fd_cli);

            continue ;

        }

        ibuf[ret] = 0;

        fx_log(log_id, "tot.log",_FL_, "接收数据[%d]", ret);

 

        /* 业务逻辑处理 */

        if (0 != BUSIService(NULL, ibuf, ret,&obuf, &len))

        {

            fx_log(log_id, LOG_FILE, _FL_,"BUSIService error");

        }

 

        if (obuf) free(obuf);

    }

 

    return 0;

}

 

 

staticint BUSIService(const char * _info, char * _imsg_data, int _ilen, char **_omsg_data, int * _olen)

{

    /* 简化处理,只是返回 SUCCESS */

    char szMsg[32];

   

    /* 模拟业务逻辑处理过程, 延时20ms */

    usleep(20000);

 

    sprintf(szMsg, "SUCCESS bytest1");

    write(fd_cli, szMsg, 16);

 

    close(fd_cli);

    fd_cli = -1;

 

    return 0;

}

 

其中fx_server 和 fx_accept的函数实现如下:

 

intfx_server( const char * _ip, const int _port )

{

    struct sockaddr_in sa;

    int on = 1;

    int fd;

 

    fd = socket( AF_INET, SOCK_STREAM, 0 );

    if( fd < 0 )

    {

        return -1;

    }

 

    setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char* ) &on , sizeof( on ) );

 

    memset( &sa, 0x00, sizeof( sa ) );  /* Probably unecessary  */

    sa.sin_family = AF_INET ;

    if (NULL == _ip || 0 == strlen(_ip))

    {

        sa.sin_addr.s_addr = htonl(INADDR_ANY);

    }

    else

    {

        sa.sin_addr.s_addr = inet_addr(_ip);

    }

    sa.sin_port = htons( _port );

 

    if( bind( fd, ( struct sockaddr * ) &sa,sizeof( sa ) ) < 0 )

    {

        close( fd );

        return -1;

    }

 

    listen( fd, 500 );            /* max # of queued connects */

 

    return fd;

}

 

 

intfx_accept( const int fd, struct sockaddr_in * cli_adr )

{

    int newfd;

 

    socklen_t dummy = sizeof( *cli_adr );

    newfd = accept( fd, ( struct sockaddr * )cli_adr, &dummy );

 

    return newfd;

}

 

程序很简单,基本的TCP服务程序,其中日志函数fx_log我封装在自己的实用库(libfx.a)中。其中业务逻辑部分也很简单,延时20ms模拟业务处理过程,然后返回”SUCCESS by test1”,见上面的BUSIService函数。(顺便说一下,本人曾使用英文名Felix,所以函数名/文件名前使用fx_前缀)

Makefile文件如下:

include${WORKDIR}/etc/Custom.defines

 

NAME=TEST1

 

CUSTOMLIB=./main.o${WORKDIR}/lib/libfx.a

EXECOBJ=${WORKDIR}/bin/${NAME}

LINKRULE=${CC}-o ${EXECOBJ} ${REGISTC} ${CUSTOMLIB} ${LIBOPTS}

 

REGISTC=

TARGETS=${EXECOBJ}

 

all:${TARGETS}

clean:

     @- rm -f ${CLEANFILES} ${TARGETS}

 

${EXECOBJ}:${CUSTOMLIB}

     ${LINKRULE}

 

编译一下:

[platdev@localhostTEST1]$ make

gcc  -g -D_ALL_SOURCE -DAREV_PINSERT-I/home/platdev/include  -o main.o -cmain.c

gcc-o /home/platdev/bin/TEST1  ./main.o/home/platdev/lib/libfx.a    -lrt -ldl-lm -lc

[platdev@localhostTEST1]$

 

启动服务:

[platdev@localhostTEST1]$ echo $PATH

/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/platdev/bin:/home/platdev/bin:/bin:.:/home/platdev/bin:/home/platdev/scripts:/home/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值