网络服务端开发小结(短连接、长连接、进程池、线程池)

     平时对网络编程方面比较感兴趣,看了一些相关的资料,自己也尝试写过一些不同网络模型的服务程序。这次刚好有一个新的需求,需要开发一个转发服务器。之前开发的项目,网络通讯都是处理联机交易的,网络连接都是采用短连接,这次的服务端,采用长连接的方式。 

1. 轮询和主动通知选择  

      公司有一个客户端产品(CLIENT),因为需要从多个客户的服务端获(SERVER)取信息,原有的设计是每个客户端通过SOCKET不断的轮询访问服务端获取信息。当CLIENT的数量不多时,轮询访问对服务端压力不大,但是当CLIENT的数量比较多时,这样的访问对服务器的压力就比较大,而且很低效。为了降低CLIENT对服务端的压力和提高信息的获取效率,采用让SERVER主动通知CLIENT的方式。不可能让每个客户SERVER都开发一个通知的服务端,所以需要一个和SERVER通讯并且把消息通知给CLIENT的转发服务端(简称TransmitServer).系统整体架构如下:

                                       SERVER    -------------->       RECV   ------->  TransmitServer—————>CLIENT

      SERVER把消息发给RECV, RECV通过消息队列发给TransmitServer,TransmitServer再把消息通知给相应的CLIENT。

2.短连接和长连接选择

   因为是通知消息的方式,所以如果使用短连接的话,让TransmitServer去和ClENT主动建立连接是不可行的,那样就要让TransmitServer知道所有CLIENT的通讯地址,这是一种很笨的方式,所以不采用。当然如果使用短连接轮询的方式,让CLIENT去访问TransmitServer,TransmitServer访问SERVER,对SERVER的压力也能得到解决.

3.  进程管理方式和I/O复用的选择

     网络连接处理的模型有很多,按照进程的管理方式,我分为2类,进程池和多进程(还包括线程),以及每种方式还可以选择是否应该使用I/O复用。

     这里说的进程池和多进程是,进程池是预先启动多个子进程,并且可以管理进程;多进程是指到主进程阻塞于ACCEPT处理连接请求,由子进程 单独负责每个套接口连接。

     处理短连接连接,因为客户端频繁的连接服务器和断开连接,服务端的主要性能开销应该是在进程切换上,基于性能考虑采用进程池的方式会比多进程好.如果连接并发量不大,没有性能上的问题,多进程的程序会比进程池简单很多。

     如果服务端处理的是长连接。如果让进程池或者多进程中一个子进程只处理一个连接,系统的主要性能开销主要取决于进程的数量,在进程的数量到一定数量的时候,会对服务器造成比较大的压力。所以在处理长连接时,一般才用I/O多路复用的方式,LINUX上I/O多路复用,有SELECT、EPOLL等。

     使用I/O多路复用一方面可以让单个进程同时多个连接,可以提高并发连接数。另一方面,还可以可以让CLIENT和SERVER的通讯更加灵活,例如使用I/O多路复用,让CLIENT和SERVER可以很容易的异步通讯。 

4. 线程和进程的选择

    使用I/O多路复用,让单个进程可以处理多个连接,如果进程池只有一个进程, 同一个服务进程里的连接之间可以很方便的通讯,但是如果是多个子进程,那么子进程之间就不能直接通讯,通常要要消息队列、共享内存、管道等。当服务端需要处理连接之间的交互,而且性能上需要多个进程,那么使用线程池代替进程池应该是一种比较好的方式。线程和进程相比较,线程的优点是性能开销更小,因为在同一个进程空间里,线程之间的通讯很容易;因为线程共享进程空间数据,因此线程在处理的时候比进程更容易出错,线程池的方式简化了通讯方式,但是为了线程安全,这方面的复杂性就增加了。所以如果网络连接之间并不需要很多交互,每个连接处理都是独立的,那么应该选择进程。这个原则不但对网络处理,对于别的处理也是如此。

    综合上面几点服务端网络模型的选择,主要是根据业务选择使用长连接或者短连接,根据连接方式。长连接一般使用线程池+I/O复用,例如网络游戏、聊天室等。短连接一般是进程池或者多进程,因为短连接不需要连接之间的交互,每个连接都是独立的,所以使用进程更加合适。

 

参考书目:

 W.Richard Stevens <<UNIX网络编程(第一卷)>>

 W.Richard Stevens <<UNIX高级环境编程>>

 

DEMO示例:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <memory.h>

#include <sys/timeb.h>
#include <time.h>
#include <sys/time.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/un.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>

#define SETSIZE 3000
#define MAXLINE 1000
#define LISTENQ 2000
#define CHILDMAX 0
#define NMERIDLEN 6
#define NUSRIDLEN 40
#define NHANDHEADLEN 12
#define NTESTPACKETLEN 1
#define NPACKETHEADLEN 4
#define NMAXPACKETLEN 256
#define TICKTIME 200000
#define TCP_CLOSE -101
#define TCP_PACKET_AVILD -102
int children[ CHILDMAX ];
int ChildNum;

 

typedef struct STRU_LINK_LIST{
        char    saMerId[ NMERIDLEN + 1 ];
        char    saUsrId[ NUSRIDLEN + 1 ];
        int     socket;
} STRULINKLIST;

STRULINKLIST client[ SETSIZE ];

typedef struct STRU_HAND_PACKET{
        char saMerId[ NMERIDLEN+1 ];
        char saUsrId[ NUSRIDLEN+1 ];
        char saHead[ NHANDHEADLEN+1 ];
}STRUHANDPACKET;

typedef struct STRU_TEST_PACKET{
        char saPacket[ NTESTPACKETLEN+1 ];
}STRUTESTPACKET;

typedef struct STRU_NOTIFY_PACKET{
        char    saMerId[ NMERIDLEN + 1 ];
        char    saU

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值