Linux网络编程服务器模型选择之并发服务器(下)
前面两篇文章(参见)分别介绍了循环服务器和简单的并发服务器网络模型,我们已经知道循环服务器模型效率较低,同一时刻只能为一个客户端提供服务,而且对于TCP模型来说,还存在单客户端长久独占与服务器的连接,无法再响应其他连接,对于前面介绍的并发服务器模型是比较简单的,比如由于预先分配了固定进程数目,就导致无法动态调整等问题。在前面我们也提到了对accept函数的处理是区分不同服务器模型的一个重要依据,当然UDP服务器并不需要accept函数,因此本次主要介绍TCP的高级并发模型。按照对accept的不同处理,接下来主要介绍以下几种并发模型:
- 单客户端单进程,统一accept :服务器主进程等待客户端连接,一旦有连接到来,就创建一个进程用于响应;
- 单客户端单线程,统一accept :服务器主进程等待客户端连接,一旦有连接到来,就创建一个线程用于响应;
- 单客户端单线程,各自accept :预先分配多个线程,在每一个线程里都独自等待客户端的连接并响应(注意accept需要互斥访问);
并发模型伪代码
/* 单客户端单进程,统一accept */
/* 服务器主进程 */
socket();
bind();
listen();
while()
{
accept();
fork();//子进程
}
close(); //关闭服务器端套接字 /* 服务器子进程1 */
recv();
process();
send();
close();//关闭客户端套接字 /* 服务器子进程2(同上) */
..................
/* 单客户端单线程,统一accept */
/* 服务器主进程 */
socket();
bind();
listen();
while()
{
accept();
pthread_create(); //创建响应线程
}
close();//关闭服务器端套接字 /* 服务器线程1 */
recv();
process();
send();
close();//关闭客户端套接字
/* 服务器线程2(同上) */
..................
/* 单客户端单线程,各自accept */
/* 服务器主进程 */
socket();
bind();
listen();
pthread_create();//创建多个线程分别等待客户端连接
pthread_join();//等待线程结束
close();//关闭服务器端套接字 /* 服务器线程1 */
mutex_lock()//互斥锁
accept();
mutex_unlock(); recv();
process();
send();
close();//客户端套接字
/* 服务器线程2(同上) */
..................
一个高级并发服务器模型的例子
单客户端单进程,统一accept server端程序
/* 单客户端单进程,统一accept --server端程序*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#define BUFFLEN 1024
#define SERVER_PORT 12348
#define BACKLOG 5 static void handle_request(int s_c)
{
time_t now;
char buff[BUFFLEN];
int n = ;
memset(buff, , BUFFLEN);
n = recv(s_c, buff, BUFFLEN,);
if(n > && !strncmp(buff, "TIME", ))
{
memset(buff, , BUFFLEN);
now = time(NULL);
sprintf(buff, "%24s\r\n",ctime(&now));
send(s_c, buff, strlen(buff),);
} close(s_c); /*关闭客户端*/
} static void handle_connect(int s_s)
{ int s_c; /*客户端套接字文件描述符*/
struct sockaddr_in from; /*客户端地址*/
int len = sizeof(from); /*主处理过程*/
while()
{
s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客户端连接*/
if(s_c > )/*客户端成功连接,创建进程进行数据处理*/
{
if(fork() > ) /*父进程*/
{
close(s_c); /*关闭父进程的客户端连接套接字*/
}
else
{
handle_request(s_c);/*处理连接请求*/
}
}
}
} int main(int argc, char *argv[])
{
int s_s; /*服务器套接字文件描述符*/
struct sockaddr_in local; /*本地地址*/ /*建立TCP套接字*/
s_s = socket(AF_INET, SOCK_STREAM, ); /*初始化地址*/
memset(&local, , sizeof(local));
local.sin_family = AF_INET;/*AF_INET协议族*/
local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
local.sin_port = htons(SERVER_PORT);/*服务器端口*/ /*将套接字文件描述符绑定到本地地址和端口*/
int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
err = listen(s_s, BACKLOG);/*侦听*/ /*处理客户端连接*/
handle_connect(s_s); close(s_s); return ;
}
单客户端单进程,统一accept server端程序
单客户端单进程,统一accept server端程序
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <string.h>
#include <pthread>
#include <stdio.h>
#define BUFFLEN 1024
#define SERVER_PORT 12348
#define BACKLOG 5 static void *handle_request(void *argv)
{
int s_c = *((int*)argv);
time_t now;
char buff[BUFFLEN];
int n = ;
memset(buff, , BUFFLEN);
n = recv(s_c, buff, BUFFLEN,);
if(n > && !strncmp(buff, "TIME", ))
{
memset(buff, , BUFFLEN);
now = time(NULL);
sprintf(buff, "%24s\r\n",ctime(&now));
send(s_c, buff, strlen(buff),);
} close(s_c); /*关闭客户端*/
} static void handle_connect(int s_s)
{
int s_c; /*客户端套接字文件描述符*/
struct sockaddr_in from; /*客户端地址*/
int len = sizeof(from);
pthread_t thread_do; /*主处理过程*/
while()
{
s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客户端连接*/
if(s_c > )/*客户端成功连接,创建线程进行数据处理*/
{
int err = pthread_create(&thread_do,NULL,handle_request,(void*)&s_c;
}
}
} int main(int argc, char *argv[])
{
int s_s; /*服务器套接字文件描述符*/
struct sockaddr_in local; /*本地地址*/ s_s = socket(AF_INET, SOCK_STREAM, );/*建立TCP套接字*/ /*初始化地址*/
memset(&local, , sizeof(local));
local.sin_family = AF_INET;/*AF_INET协议族*/
local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
local.sin_port = htons(SERVER_PORT);/*服务器端口*/ /*将套接字文件描述符绑定到本地地址和端口*/
int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
err = listen(s_s, BACKLOG);/*侦听*/ /*处理客户端连接*/
handle_connect(s_s); close(s_s); return ;
}
单客户端单线程,各自accept --server端程序
/** 单客户端单线程,各自accept --server端程序 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <pthread>
#define BUFFLEN 1024
#define SERVER_PORT 12348
#define BACKLOG 5
#define CLIENT_NUM 3 pthread_mutex_t g_lock = PTHREAD_MUTEX_INTIALIZER; static void *handle_request(void *argv)
{
int s_s = *((int*)argv); //服务器端套接字
struct sockaddr_in from; /*客户端地址*/
int len = sizeof(from);
int s_c = -; //客户端套接字
for( ; ; )
{
time_t now;
char buff[BUFFLEN];
int n = ;
memset(buff, , BUFFLEN); pthread_mutex_lock(&g_lock);
s_c = accept(s_s,(struct sockaddr*)&from, &len);
pthread_mutex_unlock(&g_lock); n = recv(s_c, buff, BUFFLEN,);
if(n > && !strncmp(buff, "TIME", ))
{
memset(buff, , BUFFLEN);
now = time(NULL);
sprintf(buff, "%24s\r\n",ctime(&now));
send(s_c, buff, strlen(buff),);
}
close(s_c); /*关闭客户端*/
} return NULL;
} static void handle_connect(int s_s)
{
int s_s = s;
pthread_t thread_do[CLIENT_NUM];
for(int i=; i<CLIENT_NUM;++i)
{
int err = pthread_create(&thread_do[i],NULL,handle_request,(void*)&s_s;
} //等待线程结束
for(int i=; i<CLIENT_NUM;++i)
pthread_join(thread_do[i],NULL);
} int main(int argc, char *argv[])
{
int s_s; /*服务器套接字文件描述符*/
struct sockaddr_in local; /*本地地址*/ s_s = socket(AF_INET, SOCK_STREAM, );/*建立TCP套接字*/ /*初始化地址*/
memset(&local, , sizeof(local));
local.sin_family = AF_INET;/*AF_INET协议族*/
local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
local.sin_port = htons(SERVER_PORT);/*服务器端口*/ /*将套接字文件描述符绑定到本地地址和端口*/
int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
err = listen(s_s, BACKLOG);/*侦听*/ handle_connect(s_s);/*处理客户端连接*/ close(s_s); return ;
}
Linux网络编程服务器模型选择之并发服务器(下)的更多相关文章
- Linux网络编程服务器模型选择之并发服务器(上)
与循环服务器的串行处理不同,并发服务器对服务请求并发处理.循环服务器只能够一个一个的处理客户端的请求,显然效率很低.并发服务器通过建立多个子进程来实现对请求的并发处理.并发服务器的一个难点是如何确定子 ...
- Linux网络编程服务器模型选择之循环服务器
在网络程序里面,通常都是一个服务器处理多个客户机,为了出个多个客户机的请求,服务器端的程序有不同的处理方式.本节开始介绍Linux下套接字编程的服务器模型选择,主要包括循环服务器模型.并发服务器模型. ...
- Linux网络编程服务器模型选择之IO复用循环并发服务器
在前面我们介绍了循环服务器,并发服务器模型.简单的循环服务器每次只能处理一个请求,即处理的请求是串行的,效率过低:并发服务器可以通过创建多个进程或者是线程来并发的处理多个请求.但是当客户端增加时,就需 ...
- Linux网络编程(简单的时间获取服务器)
1.一个简单的服务器时间获取程序 服务器和客户端采用UDP通信的方式,来编写一个简单的时间获取应用. 把过程大致理顺一下,首先是服务器端的编写,使用的是迭代的方式,没有并发 先创建一个socket而后 ...
- linux网络编程学习笔记之五 -----并发机制与线程�
进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我仅仅是举几个样例作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省 ...
- Linux网络编程(二)
Linux网络编程(二) 使用多进程实现服务器并发访问. 采用多进程的方式实现服务器的并发访问的经典范例. 程序实现功能: 1.客户端从标准输入读入一行文字,发送到服务器. 2.服务器接收到客户端发来 ...
- Linux网络编程——tcp并发服务器(poll实现)
想详细彻底地了解poll或看懂下面的代码请参考<Linux网络编程——I/O复用之poll函数> 代码: #include <string.h> #include <st ...
- 服务器编程入门(4)Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字( ...
- Linux 高性能服务器编程——Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字(so ...
随机推荐
- 前端福利之HTML5 UTF-8 中文乱码(转)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- cmake 语法
语法说明 CMakeLists.txt 文件遵循一种简单的语法包括 注释,命令和空格字符.注释使用#符号,从符号开始之后的一行都表示注释.命令包括命令名,左括号,分隔参数的空白字符和右括号.命令既可以 ...
- (转)C# .net微信开发,开发认证,关注触发消息,自动应答,事件响应,自定义菜单
原文地址:http://www.cnblogs.com/qidian10/p/3492751.html 成为开发者 string[] ArrTmp = { "token", Req ...
- ZOJ3703 Happy Programming Contest 2017-04-06 23:33 61人阅读 评论(0) 收藏
Happy Programming Contest Time Limit: 2 Seconds Memory Limit: 65536 KB In Zhejiang University P ...
- POJ 3977 Subset(折半枚举+二分)
SubsetTime Limit: 30000MS Memory Limit: 65536KTotal Submissions: 6754 Accepted: 1277 D ...
- TestNG(一)——起步
你可以从 http://testng.org/doc/documentation-main.html 获取信息. 一.简介 TestNG是test next generation的缩写,即下一代测试技 ...
- TL-WN725N v2.0 树莓派驱动
TL-WN725N 1.0版Pi是可以直接识别的,但是后来TL-WN725N又出了个2.0版的,要用第三方驱动. 安装步骤如下: wget https://dl.dropboxusercontent. ...
- Linq使用中的ToList注意事项
在使用Linq时,如果查询逻辑太复杂,可以拆分为多个Linq查询,下一个Linq在上一个Linq查询的结果上继续操作,这样逻辑清晰,又不会出错.但在使用ToList的时候需要注意,最常见碰到的错误是: ...
- Buffer Pool--内存总结1
物理地址空间是处理器用来访问位于总线上的所有部件的集合.在32位处理器上,地址总线为32位,寻址空间为4GB.在使用PAE的32位服务器上,地址总线为36位,寻址空间为64GB.在64位的处理器上生产 ...
- c# .NET RSA结合AES加密服务端和客户端请求数据
这几天空闲时间就想研究一下加密,环境是web程序,通过js请求后台返回数据,我想做的事js在发送请求前将数据加密,服务端收到后解密,待服务端处理完请求后,将处理结果加密返回给客户端,客户端在解密,于是 ...