精华内容
下载资源
问答
  • Linux服务器 线程数和系统线程

    千次阅读 2018-11-07 10:02:00
    1.查看服务器系统允许的最大线程数 ulimit -a 2. 修改配置文件 vi /etc/security/limits.d/90-nproc.conf 可以修改允许最大的线程数 3.查看当前系统比较好资源的线程 top -H 4.ps -ef|grep tomcat (查看tomcat...

    1.查看服务器系统允许的最大线程数
    ulimit -a
    在这里插入图片描述
    2. 修改配置文件
    vi /etc/security/limits.d/90-nproc.conf
    可以修改允许最大的线程数
    3.查看当前系统比较好资源的线程
    top -H
    在这里插入图片描述
    4.ps -ef|grep tomcat (查看tomcat进程)如tomcat pid进程号为 5750

    ps -Lf |wc -l -f 为全格式形式 wc为管道命令 word count 统计 -l 为统计行数
    在这里插入图片描述

    5.查询当前整个系统已用的线程或进程数
    pstree -p|wc -l
    在这里插入图片描述
    3,4为排查当前系统某个进程下的线程数,进而和5比较是否超出了当前系统允许的最大线程数,防止系统开辟不出新的线程,进而web应用抛出了can not create a native thread 的异常
    6.top -p pid 动态查看某个进程的资源消耗情况
    在这里插入图片描述

    展开全文
  • 这是在公司同事那里看到的一本书,写的是linux线程服务器编程
  • LINUX线程网络服务器设计.pdf
  • 本书主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服 务程序的主流常规技术, 重点讲解一种适应性较强的多线程服务器的编 程模型, 即one loop per thread。
  • 如何设计http服务器,及其实现过程,多线程linux,如何设计http服务器,及其实现过程,多线程linux如何设计http服务器,及其实现过程,多线程linux
  • linux线程服务器

    千次阅读 2018-05-29 15:55:58
    上一篇文章使用fork函数实现了多进程并发服务器,但是也提到了一些问题:fork是昂贵的。fork时需要复制父进程的所有资源,包括内存映象、描述字等;目前的实现使用了一种写时拷贝(copy-on-write)技术,可有效避免...

    上一篇文章使用fork函数实现了多进程并发服务器,但是也提到了一些问题:

    1. fork是昂贵的。fork时需要复制父进程的所有资源,包括内存映象、描述字等;
    2. 目前的实现使用了一种写时拷贝(copy-on-write)技术,可有效避免昂贵的复制问题,但fork仍然是昂贵的;
    3. fork子进程后,父子进程间、兄弟进程间的通信需要进程间通信IPC机制,给通信带来了困难;
    4. 多进程在一定程度上仍然不能有效地利用系统资源;
    5. 系统中进程个数也有限制。

      下面就介绍实现并发服务器的另外一种方式,使用多线程实现。多线程有助于解决以上问题。

    线程基础

      关于线程的概念就不介绍了,先了解一下linux下线程的一些基本操作。

    线程基础函数

    • pthread_create 创建线程

      pthread_create 函数用于创建新线程。当一个程序开始运行时,系统产生一个称为初始线 程或主线程的单个线程。额外的线程需要由 pthread_create 函数创建。 pthread_create 函数原型如下:

    #include <pthread.h> 
    int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *arg); 

      如果新线程创建成功,参数 tid 返回新生成的线程 ID。一个进程中的每个线程都由一个 线程 ID 标识,其类型为 pthread_t。attr 指向线程属性的指针。每个线程有很多属性包括:优 先级、起始栈大小、是否是守护线程等等。通常将 attr 参数的值设为 NULL,这时使用系统 默认的属性。 
      但创建完一个新的线程后,需要说明它将执行的函数。函数的地址由参数 func 指定。该函数必须是一个静态函数,它只有一个通用指针作为参数,并返回一个通用指针。该执行函 数的调用参数是由 arg 指定,arg 是一个通用指针,用于往 func 函数中传递参数。如果需要传递多个参数时,必须将它们打包成一个结构,然后让 arg 指向该结构。线程以调用该执行 函数开始。 
      如果函数调用成功返回 0,出错则返回非 0。

      常见的返回错误值:

    EAGAIN:超过了系统线程数目的限制。
    ENOMEN:没有足够的内存产生新的线程。
    EINVAL:无效的属性attr值。

      示例代码:

    #include <pthread.h>
    #include <stdio.h>
    pthread_t  tid;
    void *ex()
    {
        printf("this is a thread");
    }
    void main()
    {
        pthread_create(&tid,NULL,ex,NULL);
    }

      给线程传递参数:

    void *function(void *arg); 
    struct ARG { 
         int connfd; 
         int other;   //other data 
     }; 
     void main()  
     { 
         struct ARG arg; 
         int connfd,sockfd; 
         pthread_t tid; 
         //...
         While(1) 
         {     
             if((connfd = accept(sockfd,NULL,NULL))== -1) 
             { 
                  //handle exception                    
              } 
              arg.connfd = connfd; 
              if(pthread_create(&tid, NULL, funtion, (void *)&arg)) 
              { 
                  // handle exception 
              } 
          } 
     } 
     void *funtion(void *arg) 
     { 
        struct  ARG info; 
        info.connfd = ((struct ARG *)arg) -> connfd; 
        info.other = ((struct ARG *)arg) -> other; 
        //… 
        close(info.connfd); 
        pthread_exit(NULL); 
     }
    • pthread_join 
        看这个函数首先提出一个概念,线程的类型。线程分为两类:可联合的和分离的。

      1. 默认情况下线程都是可联合的。可联合的线程终止 时,其线程 ID 和终止状态将保留,直到线程调用 pthread_join 函数。
      2. 而分离的线程退出后, 系统将释放其所有资源,其他线程不能等待其终止。如果一个线程需要知道另一个线程什么 时候终止,最好保留第二个线程的可联合性。

      pthread_join 函数与进程的 waitpid 函数功能类似,等待一个线程终止。 
    pthread_join 函数原型如下:

    #inlcude <pthread.h>
    int pthread_join(pthread_t tid, void **status); 

      参数 tid 指定所等待的线程 ID。该函数必须指定要等待的线程,不能等待任一个线程结束。要求等待的线程必须是当前进程的成员,并且不是分离的线程或守护线程。 
      几个线程不 能同时等待一个线程完成,如果其中一个成功调用 pthread_join 函数,则其他线程将返回 ESRCH 错误。 
      如果等待的线程已经终止,则该函数立即返回。如果参数 status 指针非空,则 指向终止线程的退出状态值。 
      该函数如果调用成功则返回 0,出错时返回正的错误码。

    • pthread_detach 
        pthread_detach 函数将指定的线程变成分离的。 pthread_detach 函数原型如下:
    #inlcude <pthread.h> 
    int pthread_detach(pthread_t tid) ;

      参数 tid 指定要设置为分离的线程 ID。

    • pthread_self 
        每一个线程都有一个 ID,pthread_self 函数返回自己的线程 ID。 pthread_self 函数原型如下:
    #inlcude <pthread.h> 
    pthread_t pthread_self(void); 

      参数 tid 指定要设置为分离的线程 ID。 函数返回调用函数的线程 ID。 
      例如,线程可以通过如下语句,将自己设为可分离的:

    pthread_detach(pthread_self()); 
    • pthread_exit 
        函数 pthread_exit 用于终止当前线程,并返回状态值,如果当前线程是可联合的,则其 退出状态将保留。 pthread_exit函数原型如下:
    #include <pthread.h> 
    void pthread_exit(void *status);

      参数 status 指向函数的退出状态。这里的 status 不能指向一个局部变量,因为当前线程 终止后,其所有局部变量将被撤销。 
      该函数没有返回值。 
      还有两种方法可以使线程终止:

    1. 启动线程的函数 pthread_create 的第三个参数返回。该返回值就是线程的终止状态。
    2. 如果进程的 main 函数返回或者任何线程调用了 exit 函数,进程将终止,线程将随之 终止。

      下面可以看一下多线程并发服务器的实例了,需要注意的是,线程建立后,父、子线程不需要关闭任何的描述符,因为线程中使用的描述符是共享进程中的数据。

    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
    #include <unistd.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>  
    #include <pthread.h>  
    
    #define PORT 1234  
    #define BACKLOG 5  
    #define MAXDATASIZE 1000  
    
    void process_cli(int connfd, struct sockaddr_in client);  
    void *function(void* arg);  
    struct ARG {  
        int connfd;  
        struct sockaddr_in client;  
    };  
    
    void main()  
    {  
        int listenfd,connfd;  
        pthread_t  tid;  
        struct ARG *arg;  
        struct sockaddr_in server;  
        struct sockaddr_in client;  
        socklen_t  len;  
    
        if ((listenfd =socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
            perror("Creatingsocket 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(server)) == -1) {  
            perror("Bind()error.");  
            exit(1);  
        }  
    
        if(listen(listenfd,BACKLOG)== -1){  
            perror("listen()error\n");  
            exit(1);  
        }  
    
        len=sizeof(client);  
        while(1)  
        {  
            if ((connfd =accept(listenfd,(struct sockaddr *)&client,&len))==-1) {  
                perror("accept() error\n");  
                exit(1);  
            }  
            arg = (struct ARG *)malloc(sizeof(struct ARG));  
            arg->connfd =connfd;  
            memcpy((void*)&arg->client, &client, sizeof(client));  
    
            if(pthread_create(&tid, NULL, function, (void*)arg)) {  
                perror("Pthread_create() error");  
                exit(1);  
            }  
        }  
        close(listenfd);  
    }  
    
    void process_cli(int connfd, struct sockaddr_in client)  
    {  
        int num;  
        char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];  
    
        printf("Yougot a connection from %s. \n ",inet_ntoa(client.sin_addr) );  
        num = recv(connfd,cli_name, MAXDATASIZE,0);  
        if (num == 0) {  
            close(connfd);  
            printf("Clientdisconnected.\n");  
            return;  
        }  
        cli_name[num - 1] ='\0';  
        printf("Client'sname is %s.\n",cli_name);  
    
        while (num =recv(connfd, recvbuf, MAXDATASIZE,0)) {  
            recvbuf[num] ='\0';  
            printf("Receivedclient( %s ) message: %s",cli_name, recvbuf);  
            int i;  
            for (i = 0; i <num - 1; i++) {  
                if((recvbuf[i]>='a'&&recvbuf[i]<='z')||(recvbuf[i]>='A'&&recvbuf[i]<='Z'))  
                {  
                    recvbuf[i]=recvbuf[i]+ 3;  
                    if((recvbuf[i]>'Z'&&recvbuf[i]<='Z'+3)||(recvbuf[i]>'z'))  
                    recvbuf[i]=recvbuf[i]- 26;  
                }  
                sendbuf[i] =recvbuf[i];  
            }  
            sendbuf[num -1] = '\0';  
            send(connfd,sendbuf,strlen(sendbuf),0);  
        }  
        close(connfd);  
    }  
    
    void *function(void* arg)  
    {  
        struct ARG *info;  
        info = (struct ARG*)arg;  
        process_cli(info->connfd,info->client);  
        free (arg);  
        pthread_exit(NULL);  
    }  

    线程安全性

      上面的示例代码服务器端的业务逻辑都比较简单,没有涉及到共享数据产生的同步问题。在某些情况下,我们需要多个线程共享全局数据,在访问这些数据时就需要用到同步锁机制。而在共享线程内的全局数据时,可以使用Linux提供的线程特定数据TSD解决。

    同步机制

      在linux系统中,提供一种基本的进程同步机制—互斥锁,可以用来保护线程代码中共享数据的完整性。 
      操作系统将保证同时只有一个线程能成功完成对一个互斥锁的加锁操作。 
      如果一个线程已经对某一互斥锁进行了加锁,其他线程只有等待该线程完成对这一互斥锁解锁后,才能完成加锁操作。

    互斥锁函数

    pthread_mutex_lock(pthread_mutex_t  *mptr)

    参数说明:

    mptr:指向互斥锁的指针。
    该函数接受一个指向互斥锁的指针作为参数并将其锁定。如果互斥锁已经被锁定,调用者将进入睡眠状态。函数返回时,将唤醒调用者。
    如果互斥锁是静态分配的,就将mptr初始化为常值PTHREAD_MUTEX_INITIALIZER。

    pthread_mutex_unlock(pthread_mutex_t  *mptr);

      用于互斥锁解锁操作。成功返回0,否则返回错误码。

    示例代码:

    #include <pthread.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    int myglobal;
    pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
    void *thread_function(void *arg) {
        int i, j;
        for (i = 0; i < 5; i++) {
            pthread_mutex_lock(&mymutex);
            j = myglobal;
            j = j + 1;
            printf(".");
            fflush(stdout);
            sleep(1);
            myglobal = j;
            pthread_mutex_unlock(&mymutex);
        }
        return NULL;
    }
    int main(void) {
        pthread_t mythread;
        int i;
        if (pthread_create(&mythread, NULL, thread_function, NULL)) {
            printf("error creating thread.");
            abort();
        }
        for (i = 0; i < 5; i++) {
            pthread_mutex_lock(&mymutex);
            myglobal = myglobal + 1;
            pthread_mutex_unlock(&mymutex);
            printf("o");
            fflush(stdout);
            sleep(1);
        }
        if (pthread_join(mythread, NULL)) {
            printf("error joining thread.");
            abort();
        }
        printf("\nmyglobal equals %d\n", myglobal);
        exit(0);
    }

    运行效果

    线程私有数据

      在多线程环境里,应避免使用静态变量。在 Linux 系统中提供 了线程特定数据(TSD)来取代静态变量。它类似于全局变量,但是,是各个线程私有的, 它以线程为界限。TSD 是定义线程私有数据的惟一方法。同一进程中的所有线程,它们的同 一特定数据项都由一个进程内惟一的关键字 KEY 来标志。用这个关键字,线程可以存取线程私有数据。 在线程特定数据中通常使用四个函数。

    • pthread_key_create
    #include <pthread.h> 
    int pthread_key_create(pthread_key_t *key, void (* destructor)(void *value)); 

      pthread_key_create 函数在进程内部分配一个标志 TSD 的关键字。 
      参数 key 指向创建的关 键字,该关键字对于一个进程中的所有线程是惟一的。所以在创建 key 时,每个进程只能调 用一次创建函数 pthread_key_create。在 key 创建之前,所有线程的关键字值是 NULL。一旦 关键字被建立,每个线程可以为该关键字绑定一个值。这个绑定的值对于线程是惟一的,每 个线程独立维护。 
       参数 destructor 是一个可选的析构函数,可以和每个关键字联系起来。如果一个关键字 的 destructor 函数不为空,且线程为该关键字绑定了一个非空值,那么在线程退出时,析构函 数将会被调用。对于所有关键字的析构函数,执行顺序是不能指定的。 
      该函数正常执行后返回值为 0,否则返回错误码。

    • pthread_once
    #include <pthread.h> 
    int pthread_once(pthread_once_t *once, void (*init) (void)); 

      pthread_once 函数使用 once 参数所指的变量,保证每个进程只调用一次 init 函数。通常 once 参数取常量 PTHREAD_ONCE_INIT,它保证每个进程只调用一次 init 函数。 
      该函数正常执行后返回值为 0,否则返回错误码。

    • pthread_setspecific
    #include <pthread.h> 
    int pthread_setspecific(pthread_key_t key, const void *value);

      pthread_setspecific 函数为 TSD 关键字绑定一个与本线程相关的值。 
      参数 key 是 TSD 关 键字。 
      参数 value 是与本线程相关的值。value 通常指向动态分配的内存区域。 
      该函数正常执行后返回值为 0,否则返回错误码。

    • pthread_getspecific
    #include <pthread.h> 
    void * pthread_getspecific(pthread_key_t key); 

      pthread_getspecific 函数获取与调用线程相关的 TSD 关键字所绑定的值。 
      参数 key 是 TSD 关键字。 
      该函数正常执行后返回与调用线程相关的 TSD 关键字所绑定的值。否则返回 NULL。

      线程安全性代码示例:

    #include <stdio.h>
    #include <pthread.h>
    pthread_key_t   key;
    void echomsg(int t)
    {
        printf("destructor excuted in thread %d,param=%d\n", pthread_self(), t);
    }
    void * child1(void *arg)
    {
        int tid = pthread_self();
        printf("thread1 %d enter\n", tid);
        pthread_setspecific(key, (void *)tid);
        sleep(2);
        printf("thread1 %d key’s %d\n", tid, pthread_getspecific(key));
        sleep(5);
    }
    void * child2(void *arg)
    {
        int tid = pthread_self();
        printf("thread2 %d enter\n", tid);
        pthread_setspecific(key, (void *)tid);
        sleep(1);
        printf("thread2 %d key’s %d\n", tid, pthread_getspecific(key));
        sleep(5);
    }
    int main(void)
    {
        pthread_t tid1, tid2;
    
        printf("hello\n");
        pthread_key_create(&key, (void *)echomsg);
        pthread_create(&tid1, NULL, child1, NULL);
        pthread_create(&tid2, NULL, child2, NULL);
        sleep(10);
        pthread_join(tid1, NULL);
        pthread_join(tid2, NULL);
        pthread_key_delete(key);
        printf("main thread exit\n");
        return 0;
    }

    运行结果

    小结

      使用多线程实现并发服务器的优点是线程的开销小,切换容易。但是由于线程共享相同 的内存区域,所以在对共享数据的进行操作时,要注意同步问题。其中线程特定数据虽然实现起来比较烦琐,但是它是将一个非线程安全 函数转换成线程安全函数的常用方法。 
      除此之外,还可以通过改变调用函数参变量的方式实现线程的安全性,这里不作介绍。 
      下一篇文章将介绍另外一种实现并发服务器的方法:I/O 多路复用。

    展开全文
  • 线程网络服务器LINUX系统中一个新的服务器设计模式,有良好的性能表现,本文在分析现有LINUX 网络服务器开发模式的基础上,指出了单线程网络服务器的优点,然后给出了单线程网络服务器的设计框架,最后对其中的关键...
  • Linux线程并发服务器编程(线程池,FTP服务器) 分享网盘下载:https://pan.baidu.com/s/1slYq8iD 密码: qbmu 内容简介 本课程从最基础的进程、线程概念讲起逐步深入,通过理论与实践结合的方式,使学员快...
    Linux多线程并发服务器编程(线程池,FTP服务器) 
    

    分享网盘下载:https://pan.baidu.com/s/1slYq8iD 密码: qbmu

    内容简介
    本课程从最基础的进程、线程概念讲起逐步深入,通过理论与实践结合的方式,使学员快说掌握linux多线程网络编程技术,并理解技术背后的实现原理。课程详细讲解了网络编程涉及的数据结构、网络协议、编程接口、g++、gdb、makefile编程工具以及netstat、lsof等相关性能调试命令。并通过实例深入剖析并发服务器程序的开发流程、架构设计、运行原理、性能调优以及异步I/O模型、线程池、多线程并发控制、线程间通信等关键技术。

    课程共分四个部分:
    第一部分是linux网络编程基础理论介绍,该部分讲解了linux多线程网络编程用到的基本理论知识;

    第二部分为基本网络编程,介绍了linux编程基本工具使用,重点介绍了TCP套接字编程和UDP套接字编程;

    第三部分是高级网络编程,主要介绍了套接字选项、多种IO模型以及并发服务器用到的线程池技术;

    第四部分为项目案例,讲解了FTP并发服务器程序的实现。


    第一部分:网络编程理论基础
    第一讲:进程的引入及定义
    第二讲:进程的特征及状态
    第三讲:进程的调度
    第四讲:线程的引入及定义
    第五讲:线程的分类
    第六讲:线程的互斥
    第七讲:线程的同步
    第八讲:线程同步与互斥案例分析(1)
    第九讲:线程同步与互斥案例分析(2)
    展开全文
  • linux下多线程文件服务器 http://blog.csdn.net/ce123_zhouwei/article/details/17066313文章的附件
  • 摘要:单线程网络服务器linux系统中一个新的服务器设计模式,有良好的性能表现,本文在分析现有linux网络服务器开发模式的基础上,指出了单线程网络服务器的优点,然后给出了单线程网络服务器的设计框架,最后对...

    摘要:单线程网络服务器是linux系统中一个新的服务器设计模式,有良好的性能表现,本文在分析现有linux网络服务器开发模式的基础上,指出了单线程网络服务器的优点,然后给出了单线程网络服务器的设计框架,最后对其中的关键技术进行了阐述。 

    一、引言 
    linux以其良好的稳定性被广泛地作为服务器程序的运行平台,特别是现在众多的网络服务器,比如apache、openvpn等,都运行于linux平台之上。与windows系统相比,linux系统具有更高的稳定性和可扩展性,因此,linux已成为网络服务器开发的首选平台。 
    与一般程序不同,网络服务器程序要求高的稳定性和一定的性能,而传统的多线程的开发方式存在众多缺点,总结起来主要有如下: 
    首先:大用户量时,线程切换开销大,服务器性能严重下降; 
    其次:线程间共享变量容易冲突,影响稳定性,如果变量锁太多,又影响服务器的处理性能; 
    最后:linux原生不支持多线程,操作系统级对线程支持不好。 
    因此,采用多线程的方法很难开发出高性能稳定的服务器,本文分析了除多线程外的几种网络服务器程序设计模式,并详细说明了单线程网络服务器程序的开发设计方法。 
    二、linux网络服务器常见设计模式分析 

    除了多线程模式外,linux网络服务器还有线程池、多进程、prefork子进程,阻塞迭代、单线程等。

    一)线程池技术由服务器进程维护一个线程池,在这个池里预先创建了若干个线程,当一个用户连接接入时,就从线程池里取出一个线程进行工作,当连接关闭时,就将该线程放回到连接池中。这种方式减少了线程初始化的时间,加快了连接接入的速度,但是该方式并没有真正解决多线程程序线程切换、共享变量带来的性能问题。 
    (二)多进程技术是为每个用户连接创建一个进程,进程间不像多线程那样连接紧密,其共享变量的方法一般通过共享内存等机制,该方式减少了共享变量带来的开销,但是大量用户在线时,其性能依然较低。 
    (三)prefork子进程模式是由主进程预先创建一些子进程,其采用某个算法,根据用户量动态地有准备地创建多个子进程,常用的apache服务器便是采用该种方式,该方式节约了进程创建时间,但是当大量用户连接存在时,其进程切换开销也是惊人的。 
    (四)阻塞迭代服务器中只存在一个进程,该进程处理完一个请求后,再处理另外一个,该方式适用于少量用户接入的情况,当处理一个用户时间比较长时,可能耽误其它用户的处理,一般网络服务器很少采用该方式。 
    (五)单线程服务器与迭代服务器类似,也是由一个进程处理所有请求,该进程只有一个主线程在运行,并不创建其它的线程,nginx、lighttpd等服务器便是采用的这种方式,该方式由一个程序来模拟cpu的切换,减少了大量用户访问时的切换开销,在处理io时采用非阻塞的方式,防止了某个连接处理超时而耽误其它用户连接的处理。 
    单线程服务器开销小,能够支持大量用户在线,是一种比较好的方式。然而该方式需要保存每个用户处理现场和精确的用户处理时间片控制,对程序设计实现要求较高,下面重点说明如何设计实现单线程网络服务器。 
    三、单线程网络服务器的设计 
    一个基本的单线程网络服务器模块如图所示,主要由初始化模块、主循环模块、定时处理模块、连接接入处理模块、连接业务处理模块、读处理模块、写处理模块、断开处理模块等构成。 

    图1单线程网络服务器模块结构 
    初始化模块负责程序的一些初始化工作,比如配置文件的读取、监听socket的创建、必要参数的设置等。 
    主循环模块是一个死循环处理,其负责监听每一个socket事件,当有事件发生时,调用相关socket的处理函数进行处理,处理的事件包括定时事件、连接接入事件、和连接读、写、断开等事件,这些事件分别由不同的模块来处理。 
    定时处理模块负责处理定时触发的事件,一般1秒执行一次,负责对所有用户连接进行检查或进行一些定期的操作,主要检查的项目包括网络超时、会话超时等,定期执行操作的包括处理状态输出、垃圾回收等。 
    连接接入处理模块负责对用户接入事件进行响应,接收用户的连接,并进行相应的处理,比如为用户连接分配必要的处理资源,以及将该连接加入到监听队列里。 
    连接业务处理模块负责处理用户连接socket上所发生的一切事件的处理,主要的事件包括读、写、断开,这三个事件分别由对应的三个子模块进行处理。其中需要注意的是读、写处理模块均需要为非阻塞操作,否则会影响程序为多个用户处理的时间。 
    四、单线程网络服务器的关键技术 
    (一)非阻塞io 
    在单线程服务器中,不能由于某个连接的处理而耽误其它连接的处理,因此,当一个连接的io需要等待时,就需要去处理其它连接,而不能“死等”。非阻塞io在当前数据无法处理完毕时直接返回,而不需要调用者等待其处理完毕,节约了处理时间。 
    在linux系统中,操作系统为每个socket都分配了一个读缓冲和一个写缓冲,当执行read操作时,会将内核空间读缓冲中的内容复制到用户空间,当执行write操作时,会将用户空间的内容复制到内核写缓冲中,再由操作系统发送出去。如果内核读缓冲中的内容比较少,在阻塞的情况下,read函数会一直等待操作系统从网络读取,在非阻塞的情况下,就不会等待,因此如果一个数据分组没有读取完毕,就必须将已读数据时行缓存,等到下次有数据到达时再进行读取。对于write函数来说也是一样,如果内核写缓冲中的待写数据太多,就必须对待写数据进行缓存,当缓存可写时再进行写入。

    (二)epoll技术 
    在非阻塞io情况下,必须采用异步事件处理的方式,在主循环模块中,常用的做法是采用select函数来监听当前所有连接事件,当有事件发生时,select便返回当前发生的事件。然而select方式最大的问题在于,当有事件发生时,必须采用轮循的方式来判断是哪个连接触发了事件,这样在大量用户连接时,将会降低处理速度,另外一点是select一般最大能够监听的连接数只有1024个,对于同时需要大量连接处理的任务来说,是无法满足的。 
    从linux2.4内核开始支持了epoll技术,该技术允许当一个事件发生时,发生事件的socket将会被返回,这样,程序能够立即判断出来是哪个连接发生了事件,节约了大量的时间,而且epoll允许最大监听的连接数与操作系统本身所能够支持的最大连接数一致,因此,epool特别适用于同时处理大量大线连接的网络服务器。 
    五、结论 
    单线程网络服务器是一种新的服务器设计模式,相对于其它服务器开发模式,其具有良好的性能,特别是对于大量用户连接同时在线的网络服务器来说,单线程模式是非常适合的。


    关于服务器设计模式:单线程,协程等新概念

    展开全文
  • linux线程并发服务器(TCP)

    千次阅读 2018-08-27 09:24:10
    linux线程并发服务器(TCP) ​ 所谓多线程并发服务器就是基于线程,每个客户端来了创建一个线程,由线程去处理客户端的请求。相对于多线程服务器来说,多进程服务器在创建进程时要消耗较大的系统资源,所以我们...
  • Muduo :用于Linux线程服务器的C 非阻塞网络库
  • LinuxC编程一站式学习.pdf unix程序员手册.pdf 多线程服务器的常用编程模型.pdf 网络编程模型综述.doc 高性能高并发服务器架构.rar Linux环境并发服务器设计技术研究.pdf 应用SELECT模型实现TCP并发服务器.pdf ...
  • linux服务器查看进程、线程数量

    万次阅读 2019-10-23 09:07:22
    linux服务器查看进程、线程数量 查看进程总数 ps -ef | wc -l 查看某个服务的进程数 eg:http服务: ps -ef | grep httpd | wc -l 查看物理cpu个数 grep 'physical id' /proc/cpuinfo | sort -u 查看...
  • 资源内容是Linux线程服务端编程 - 陈硕(高清完整版),带标签。已经用软件分析成“分子版”。
  • Linux线程服务器-门禁打卡系统

    千次阅读 2015-09-09 10:52:39
    系统采用一个服务器+两种客户端(网页+APP)OpenDoorMultiThreadServerOpenDoorMultiThreadServer 实验室门禁打卡系统 1、mydb是操作数据库Mysql类,表示每个人员身份的唯一标准是提前分配的不同的局域网IP 2、...
  • 目前Linux平台的Web服务器主要基于进程或线程机制,面对大数量的并发请求,延时现象较为明显。这主要原因在于服务器存在着利用率不高,资源消耗大等问题。文中利用信号量机制和生产者一消费者模型,设计基于多线程池...
  • linux服务器查询java线程占用的资源

    千次阅读 2018-08-23 13:44:42
    2、用 top -H -p 86184 ,查询该进程下的线程资源   3、使用jstack 86184 &gt; jstack.txt ,输出 该进程下的线程信息, 4、比如,观察到86344这个线程占用cpu 大, 将十进制的86344 转换成16进制 15148  ...
  • 基于Linux环境日志服务器线程调度问题.pdf
  • 本书重点讲解多线程网络服务器的一种IO模 型, 即one loop per thread。 这是一种适应性较强的模型, 也是Linux下以 native语言编写用户态高性能网络程序最成熟的模式, 掌握之后可顺利 地开发各类常见的服务端网络...
  • linux下多线程网络编程TCP服务器端数据传输代码,C语言程序,使用前请阅读readme.txt
  • 鱼还是熊掌:浅谈多进程多线程的选择 关于多进程和多线程,教科书上最经典的一句话是“进程是资源分配的最小单位,线程是CPU调度的最小...”、“Linux下用多进程还是多线程?”等等期望一劳永逸的问题,我只能说:没有
  • 推荐《Linux线程服务器端编程》

    万次阅读 2013-08-26 23:55:56
    我推荐了《Linux线程服务器端编程——使用 muduo C++ 网络库》给他,他在网上书店了以后问我为什么推荐这么厚一本书给他,正好这本书我已经早就完了,一直也想写篇“书评”,就在这里多扯几句。其实实在算不...
  • 上一篇文章使用fork函数实现了多进程并发服务器,但是也提到了一些问题: fork是昂贵的。fork时需要复制父进程的所有资源,包括内存映象、描述字等; 目前的实现使用了一种写时拷贝(copy-on-write)技术,可有效...
  • 这本书确实是学习多核时代采用现代C++编写多线程程序的好书,下面是学习总结: 第一章线程安全的对象生命期管理 对象的创建很简单,但是不要在构造期间泄漏this指针,比如不要在构造函数中注册任何回调函数,二...
  • linux_socket_多线程服务器端代码,包含两套实现,如有问题,欢迎留言指正2006sszgg@163.com。
  • 本书信息 《 Linux高性能服务器编程... chenshuo / muduo:事件驱动的网络库,用于C ++ 11中的多线程Linux服务器 qinguoyi / TinyWebServer:Linux下C ++轻量级Web服务器 linyacool / WebServer:C ++高性能Web服务器
  • 我推荐了《Linux线程服务器端编程——使用 muduo C++ 网络库》给他,他在网上书店了以后问我为什么推荐这么厚一本书给他,正好这本书我已经早就完了,一直也想写篇“书评”,就在这里多扯几句。其实实在算不...
  • 基于Linux的预线程化并发Web服务器设计.pdf
  • 基于Linux的多线程池并发Web服务器设计.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 221,993
精华内容 88,797
关键字:

linux服务器线程怎么看

linux 订阅