`

【Linux的高级应用编程】网络编程中并发服务器的设计模式

 
阅读更多

网络编程中并发服务器的设计模式

Sailor_forever sailing_9806@163.com 转载请注明

http://blog.csdn.net/sailor_8318/archive/2008/12/30/3658912.aspx

并发服务器有三种设计模式:

多进程:每个进程服务一个客户端。优势是有各自独立的地址空间,可靠性高,但进程调度开销大,无法资源共享,进程间通信机制复杂。

多线程:每个线程服务一个客户端。优势是开销小,通信机制简单,可共享内存。但共享地址空间,可靠性低,一个服务器出现问题时可能导致系统崩溃,同时全局共享可能带来竞争,共享资源需要互斥,对编程要求高。

单进程:占有的进程及线程资源少,通信机制简单。但监听服务器及各个子服务器揉和在一起,程序结构复杂不清晰,编程麻烦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

// File: mult-pr-tcp-server.c

/*

多进程并发服务器。该程序等候客户连接,一旦连接则显示客户的地址,

接着接收该客户的名字并显示。然后接收来自该客户的信息(字符串)。

每当收到一个字符串,则显示该字符串,并将字符串反转,再将反转的字

符发回客户。之后,继续等待接收该客户的信息直至该客户关闭连接。服

务器具有同时处理多客户的能力。

*/

#include <stdio.h> /* These are the usual header files */

#include <strings.h> /* for bzero() */

#include <unistd.h> /* for close() */

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#define PORT 1234 /* Port that will be opened */

#define BACKLOG 2 /* Number of allowed connections */

#define MAXDATASIZE 1000

void process_cli(int connectfd, struct sockaddr_in client);

main()

{

int listenfd, connectfd; /* socket descriptors */

pid_t pid;

struct sockaddr_in server; /* server's address information */

struct sockaddr_in client; /* client's address information */

int sin_size;

/* Create TCP socket */

if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

/* handle exception */

perror("Creating socket failed.");

exit(1);

}

int opt = SO_REUSEADDR;

setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

bzero(&server,sizeof(server));

server.sin_family=AF_INET;

server.sin_port=htons(PORT);

server.sin_addr.s_addr = htonl (INADDR_ANY);

if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {

/* handle exception */

perror("Bind error.");

exit(1);

}

if(listen(listenfd,BACKLOG) == -1){ /* calls listen() */

perror("listen() error/n");

exit(1);

}

sin_size=sizeof(struct sockaddr_in);

while(1)

{

/*accept connection.what causes the acceptance? */

if ((connectfd = accept(listenfd,(struct sockaddr *)&client,&sin_size))==-1) {

perror("accept() error/n");

exit(1);

}

/* Create child process to service client */

if ((pid=fork())>0) {

/* parent process */

close(connectfd);

continue;

}

else if (pid==0) {

/*child process*/

close(listenfd);

process_cli(connectfd, client);

exit(0);

}

else {

printf("fork error/n");

exit(0);

}

}

close(listenfd); /* close listenfd */

}

void process_cli(int connectfd, struct sockaddr_in client)

{

int num;

char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];

printf("You got a connection from %s. ",inet_ntoa(client.sin_addr) ); /* prints client's IP */

/* Get client's name from client */

num = recv(connectfd, cli_name, MAXDATASIZE,0);

if (num == 0) {

close(connectfd);

printf("Client disconnected./n");

return;

}

cli_name[num - 1] = '/0';

printf("Client's name is %s./n",cli_name);

while (num = recv(connectfd, recvbuf, MAXDATASIZE,0))

{

int i = 0;

recvbuf[num] = '/0';

printf("Received client( %s ) message: %s",cli_name, recvbuf);

for (i = 0; i < num - 1; i++) {

sendbuf[i] = recvbuf[num - i -2];

}

sendbuf[num - 1] = '/0';

send(connectfd,sendbuf,strlen(sendbuf),0); /* send to the client welcome message */

}

close(connectfd); /* close connectfd */

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

// File: mult-thread-tcp-server.c

/*

多线程并发服务器。该程序实现多线程并发服务器

*/

#include <stdio.h> /* These are the usual header files */

//#include <strings.h> /* for bzero() only <strings.h> can not be compiled for memcpy in c++*/

#include <string.h> /* for bzero() */

#include <unistd.h> /* for close() */

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <pthread.h>

#include <stdlib.h> /* for exit in c++(.C/.cc) ; no need for c ??*/

#define PORT 1234 /* Port that will be opened */

#define BACKLOG 5 /* Number of allowed connections */

#define MAXDATASIZE 1000

//void process_cli(int connectfd, sockaddr_in client); // c only supports struct sockaddr_in, but c++ support sockaddr_in

void process_cli(int connectfd, struct sockaddr_in client);

/* function to be executed by the new thread */

void* start_routine(void* arg);

typedef struct _ARG {

int connfd;

struct sockaddr_in client;

}ARG;

// it's better to use typedef struct

main()

{

int listenfd, connectfd; /* socket descriptors */

pthread_t thread;

//struct ARG *arg; // when no typedef,there should be struct for c code; no need for c++

ARG *arg;

struct sockaddr_in server; /* server's address information */

struct sockaddr_in client; /* client's address information */

int sin_size;

/* Create TCP socket */

if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

/* handle exception */

perror("Creating socket failed.");

exit(1);

}

int opt = SO_REUSEADDR;

setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

bzero(&server,sizeof(server));

server.sin_family=AF_INET;

server.sin_port=htons(PORT);

server.sin_addr.s_addr = htonl (INADDR_ANY);

if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {

/* handle exception */

perror("Bind error.");

exit(1);

}

if(listen(listenfd,BACKLOG) == -1){ /* calls listen() */

perror("listen() error/n");

exit(1);

}

sin_size=sizeof(struct sockaddr_in);

while(1)

{

/* Accept connection */

// if ((connectfd = accept(listenfd,(struct sockaddr *)&client,&sin_size))==-1) {// no problem for c

if ((connectfd = accept(listenfd,(struct sockaddr *)&client,(socklen_t *)&sin_size))==-1) {

perror("accept() error/n");

exit(1);

}

/* Create thread*/

arg = new ARG;

arg->connfd = connectfd;

//memcpy((void *)&arg->client, &client, sizeof(client)); // both ok!

memcpy(&arg->client, &client, sizeof(client));

if (pthread_create(&thread, NULL, start_routine, (void*)arg)) {

/* handle exception */

perror("Pthread_create() error");

exit(1);

}

}

close(listenfd); /* close listenfd */

}

void process_cli(int connectfd, sockaddr_in client)

{

int num;

char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];

printf("You got a connection from %s. ",inet_ntoa(client.sin_addr) );

/* Get client's name from client */

num = recv(connectfd, cli_name, MAXDATASIZE,0);

if (num == 0) {

close(connectfd);

printf("Client disconnected./n");

return;

}

cli_name[num - 1] = '/0';

printf("Client's name is %s./n",cli_name);

while (num = recv(connectfd, recvbuf, MAXDATASIZE,0)) {

recvbuf[num] = '/0';

printf("Received client( %s ) message: %s",cli_name, recvbuf);

for (int i = 0; i < num - 1; i++) {

sendbuf[i] = recvbuf[num - i -2];

}

sendbuf[num - 1] = '/0';

send(connectfd,sendbuf,strlen(sendbuf),0);

}

close(connectfd); /* close connectfd */

}

void* start_routine(void* arg)

{

ARG *info;

info = (ARG *)arg;

/* handle client's requirement */

process_cli(info->connfd, info->client);

////delete arg will cause warning!the type for deleting should be the same as new allocated

delete info;

pthread_exit(NULL);

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

// File:singlethread-mult-tcp-server.C

/*单线程并发服务器实例。该程序采用单线程并发服务器算法实现的。*/

#include <stdio.h> /* These are the usual header files */

#include <string.h> /* for bzero() */

#include <unistd.h> /* for close() */

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <sys/time.h>

#include <stdlib.h>

#define PORT 1234 /* Port that will be opened */

#define BACKLOG 5 /* Number of allowed connections simutaniously*/

#define MAXDATASIZE 1000

typedef struct _CLIENT{

int fd;

char* name;

struct sockaddr_in addr; /* client's address information */

char* data;

} CLIENT;

void process_cli(CLIENT *client, char* recvbuf, int len);

void savedata(char* recvbuf, int len, char* data);

main()

{

int i, maxi, maxfd,sockfd;

int nready;

ssize_t n;

fd_set rset, allset;

int listenfd, connectfd; /* socket descriptors */

struct sockaddr_in server; /* server's address information */

/* client's information */

CLIENT client[FD_SETSIZE];

char recvbuf[MAXDATASIZE];

int sin_size;

/* Create TCP socket */

if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

/* handle exception */

perror("Creating socket failed.");

exit(1);

}

int opt = SO_REUSEADDR;

setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

bzero(&server,sizeof(server));

server.sin_family=AF_INET;

server.sin_port=htons(PORT);

server.sin_addr.s_addr = htonl (INADDR_ANY);

if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {

/* handle exception */

perror("Bind error.");

exit(1);

}

if(listen(listenfd,BACKLOG) == -1){ /* calls listen() */

perror("listen() error/n");

exit(1);

}

sin_size=sizeof(struct sockaddr_in);

/*initialize for select */

maxfd = listenfd;

maxi = -1;

for (i = 0; i < FD_SETSIZE; i++) {

client[i].fd = -1;

}

FD_ZERO(&allset);

FD_SET(listenfd, &allset);

while(1)

{

struct sockaddr_in addr;

rset = allset;

nready = select(maxfd+1, &rset, NULL, NULL, NULL);

printf("select saw rset actions and the readfset num is %d. /n",nready );

if (FD_ISSET(listenfd, &rset))

{ /* new client connection */

/* Accept connection */

printf("accept a connection./n");

if ((connectfd = accept(listenfd,(struct sockaddr *)&addr,(socklen_t *)&sin_size))==-1) {

perror("accept() error/n");

continue;

}

/* Put new fd to client */

for (i = 0; i < FD_SETSIZE; i++)

if (client[i].fd < 0) {

client[i].fd = connectfd; /* save descriptor */

client[i].name = new char[MAXDATASIZE];

client[i].addr = addr;

client[i].data = new char[MAXDATASIZE];

client[i].name[0] = '/0';

client[i].data[0] = '/0';

printf("You got a connection from %s. ",inet_ntoa(client[i].addr.sin_addr) );

break;

}

printf("add new connect fd./n");

if (i == FD_SETSIZE) printf("too many clients/n");

FD_SET(connectfd, &allset); /* add new descriptor to set */

if (connectfd > maxfd) maxfd = connectfd;

if (i > maxi) maxi = i;

if (--nready <= 0) continue; /* no more readable descriptors */

}

for (i = 0; i <= maxi; i++)

{

/* check all clients for data */

if ( (sockfd = client[i].fd) < 0) continue; /* no more connected clients*/

if (FD_ISSET(sockfd, &rset)) {

printf("recv occured for connect fd[%d]./n",i);

if ( (n = recv(sockfd, recvbuf, MAXDATASIZE,0)) == 0) {

/*connection closed by client */

close(sockfd);

printf("Client( %s ) closed connection. User's data: %s/n",client[i].name,client[i].data);

FD_CLR(sockfd, &allset);

client[i].fd = -1;

delete client[i].name;

delete client[i].data;

} else

process_cli(&client[i], recvbuf, n);

if (--nready <= 0) break; /* no more readable descriptors */

}

}

}

close(listenfd); /* close listenfd */

}

void process_cli(CLIENT *client, char* recvbuf, int len)

{

char sendbuf[MAXDATASIZE];

recvbuf[len-1] = '/0';

if (strlen(client->name) == 0) {

/* Got client's name from client */

memcpy(client->name,recvbuf, len);

printf("Client's name is %s./n",client->name);

return;

}

/* save client's data */

printf("Received client( %s ) message: %s/n",client->name, recvbuf);

/* save user's data */

savedata(recvbuf,len, client->data);

/* reverse usr's data */

for (int i1 = 0; i1 < len - 1; i1++) {

sendbuf[i1] = recvbuf[len - i1 -2];

}

sendbuf[len - 1] = '/0';

send(client->fd,sendbuf,strlen(sendbuf),0);

}

void savedata(char* recvbuf, int len, char* data)

{

int start = strlen(data);

for (int i = 0; i < len; i++) {

data[start + i] = recvbuf[i];

}

}


分享到:
评论

相关推荐

    Scrapy-1.8.2.tar.gz

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    search-log.zip

    搜索记录,包括时间、搜索关键词等,用于PySpark案例练习

    6-12.py

    6-12

    2-6.py

    2-6

    Scrapy-0.24.5-py2-none-any.whl

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    基于CS的远程监控系统软件项目(免费提供全套java开源项目源码+论文)

    项目介绍 背景 在当今的数字化时代,远程监控系统已经成为企业和个人必不可少的工具。随着物联网(IoT)技术的发展,监控系统的需求不断增加,不仅仅局限于视频监控,还包括数据监控、设备状态监控等。基于CS(Client-Server)架构的远程监控系统应运而生,旨在提供高效、实时、可靠的监控服务,帮助用户实现远程管理和控制。 目的 基于CS的远程监控系统软件项目旨在为用户提供一个综合性的监控平台,通过该平台,用户可以实时监控各类设备和数据,实现远程控制和管理,提高工作效率,降低运营成本。同时,该系统还可以用于安全防护、生产过程监控等多种场景,具有广泛的应用前景。 模块说明 前端模块 前端模块是用户与系统交互的界面,负责展示监控数据和接收用户指令。前端模块的主要功能包括: 用户登录与认证:通过安全的登录机制,确保只有授权用户才能访问系统。 实时数据展示:以图表、仪表盘等形式展示实时监控数据,包括视频流、传感器数据等。 报警通知:当监控系统检测到异常情况时,前端模块会通过弹窗、声音等方式通知用户。 远程控制:用户可以通过前端界面对设备进行远程控制,例如开关设备、调整参数等。

    课程大作业二手车价格预测案例数据挖掘python源码+数据集+实验报告+详细注释.zip

    课程大作业二手车价格预测案例数据挖掘python源码+数据集+实验报告+详细注释.zip

    基于springcloud和vue后台管理系统.zip

    springcloud 基于springcloud和vue后台管理系统.zip

    基于Pyotrch的深度学习物体分类可视化系统源码+预训练模型+详细训练教程.zip

    基于Pyotrch的深度学习物体分类可视化系统源码+预训练模型+详细训练教程.zip

    pytest-3.0.2.tar.gz

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    XXX公司组织结构诊断报告.ppt

    XXX公司组织结构诊断报告.ppt

    3-18-1.py

    3-18-1

    ZCU102 FPGA DDR4 MIG IP核读写接口封装与FIFO测试工程教程(配套下载资料)

    本资源提供了一份全面的教程,专注于使用ZCU102 FPGA开发板实现DDR4内存的读写操作。通过构建DDR4的MIG(Memory Interface Generator)IP核,本教程详细介绍了如何封装DDR4的读写时序,并创建了一个类似FIFO(先进先出)的接口,以优化数据流的管理和控制。此外,还包含了对所封装接口进行测试的工程实例,帮助开发者深入理解DDR4内存接口的高效应用。适合希望在FPGA项目中集成高效内存管理方案的工程师和高级学者。

    课程设计基于matlab机械臂末端轨迹规划的源码.zip

    课程设计基于matlab机械臂末端轨迹规划的源码.zip

    基于深度学习的LSTM算法双色球预测实战完整代码.zip

    基于深度学习的LSTM算法双色球预测实战完整代码.zip

    yolov5-face-landmarks-opencv

    yolov5检测人脸和关键点,只依赖opencv库就可以运行,程序包含C++和Python两个版本的。 本套程序根据https://github.com/deepcam-cn/yolov5-face 里提供的训练模型.pt文件。转换成onnx文件, 然后使用opencv读取onnx文件做前向推理,onnx文件从百度云盘下载,下载 链接:https://pan.baidu.com/s/14qvEOB90CcVJwVC5jNcu3A 提取码:duwc 下载完成后,onnx文件存放目录里,C++版本的主程序是main_yolo.cpp,Python版本的主程序是main.py 。此外,还有一个main_export_onnx.py文件,它是读取pytorch训练模型.pt文件生成onnx文件的。 如果你想重新生成onnx文件,不能直接在该目录下运行的,你需要把文件拷贝到https://github.com/deepcam-cn/yolov5-face 的主目录里运行,就可以生成onnx文件。

    matlab基于Matlab_Simulink的自主水下航行器三维路径跟踪仿真.zip

    matlab基于Matlab_Simulink的自主水下航行器三维路径跟踪仿真.zip

    麦肯锡 - 上海xx集团-完善组织架构,优化管理流程.ppt

    麦肯锡 - 上海xx集团-完善组织架构,优化管理流程.ppt

    pytest-7.3.2.tar.gz

    文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    matlab将MATLAB连接到OpenAI聊天完成API(支持ChatGPT).zip

    matlab将MATLAB连接到OpenAI聊天完成API(支持ChatGPT).zip

Global site tag (gtag.js) - Google Analytics