您的位置:首页 > 理论基础 > 计算机网络

Linux网络编程服务器模型选择之并发服务器(下)

2014-03-23 13:58 393 查看
前面两篇文章(参见)分别介绍了循环服务器和简单的并发服务器网络模型,我们已经知道循环服务器模型效率较低,同一时刻只能为一个客户端提供服务,而且对于TCP模型来说,还存在单客户端长久独占与服务器的连接,无法再响应其他连接,对于前面介绍的并发服务器模型是比较简单的,比如由于预先分配了固定进程数目,就导致无法动态调整等问题。在前面我们也提到了对accept函数的处理是区分不同服务器模型的一个重要依据,当然UDP服务器并不需要accept函数,因此本次主要介绍TCP的高级并发模型。按照对accept的不同处理,接下来主要介绍以下几种并发模型:

单客户端单进程,统一accept :服务器主进程等待客户端连接,一旦有连接到来,就创建一个进程用于响应;

单客户端单线程,统一accept :服务器主进程等待客户端连接,一旦有连接到来,就创建一个线程用于响应;

单客户端单线程,各自accept :预先分配多个线程,在每一个线程里都独自等待客户端的连接并响应(注意accept需要互斥访问);

并发模型伪代码

/* 单客户端单进程,统一accept */
/* 服务器主进程 */
socket();
bind();
listen();
while(1)
{
accept();
fork();//子进程
}
close(); //关闭服务器端套接字

/* 服务器子进程1 */
recv();
process();
send();
close();//关闭客户端套接字

/* 服务器子进程2(同上) */
..................


/* 单客户端单线程,统一accept */
/* 服务器主进程 */
socket();
bind();
listen();
while(1)
{
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 = 0;
memset(buff, 0, BUFFLEN);
n = recv(s_c, buff, BUFFLEN,0);
if(n > 0 && !strncmp(buff, "TIME", 4))
{
memset(buff, 0, BUFFLEN);
now = time(NULL);
sprintf(buff, "%24s\r\n",ctime(&now));
send(s_c, buff, strlen(buff),0);
}

close(s_c);    /*关闭客户端*/
}

static void handle_connect(int s_s)
{

int s_c;    /*客户端套接字文件描述符*/
struct sockaddr_in from;    /*客户端地址*/
int len = sizeof(from);

/*主处理过程*/
while(1)
{
s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客户端连接*/
if(s_c > 0)/*客户端成功连接,创建进程进行数据处理*/
{
if(fork() > 0)  /*父进程*/
{
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, 0);

/*初始化地址*/
memset(&local, 0, 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 0;
}


单客户端单进程,统一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 = 0;
memset(buff, 0, BUFFLEN);
n = recv(s_c, buff, BUFFLEN,0);
if(n > 0 && !strncmp(buff, "TIME", 4))
{
memset(buff, 0, BUFFLEN);
now = time(NULL);
sprintf(buff, "%24s\r\n",ctime(&now));
send(s_c, buff, strlen(buff),0);
}

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(1)
{
s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客户端连接*/
if(s_c > 0)/*客户端成功连接,创建线程进行数据处理*/
{
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, 0);/*建立TCP套接字*/

/*初始化地址*/
memset(&local, 0, 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 0;
}


单客户端单线程,各自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 = -1; //客户端套接字
for( ; ; )
{
time_t now;
char buff[BUFFLEN];
int n = 0;
memset(buff, 0, 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,0);
if(n > 0 && !strncmp(buff, "TIME", 4))
{
memset(buff, 0, BUFFLEN);
now = time(NULL);
sprintf(buff, "%24s\r\n",ctime(&now));
send(s_c, buff, strlen(buff),0);
}
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=0; i<CLIENT_NUM;++i)
{
int err = pthread_create(&thread_do[i],NULL,handle_request,(void*)&s_s;
}

//等待线程结束
for(int i=0; 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, 0);/*建立TCP套接字*/

/*初始化地址*/
memset(&local, 0, 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 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: