Unix C语言编写基于多线程的小型并发服务器

11 篇文章 0 订阅
8 篇文章 1 订阅

转自:https://my.oschina.net/zzw922cn/blog/493896

线程介绍

线程就是运行在一个进程上下文中的逻辑流,一般来说,程序是由每个进程中的单一线程来组成的。但是,我们实际上也可以编写一个进程里同时运行多个线程的程序,线程是由内核调度的,从进程间通信角度来看,一个给定进程内的所有线程共享同样的全局变量。每个线程具有独立的线程上下文,包括一个唯一的整数线程ID,栈,栈指针,程序计数器,通用目的寄存器和条件码。所有运行在一个进程中的线程共享该进程的整个虚拟地址空间。基于线程的逻辑流结合了基于进程和基于IO多路复用的流的特性,同进程一样,线程有内核自动调度,并且内核通过一个整数ID来识别线程,同基于多路IO复用一样,多个线程运行在单一进程的上下文之中,因此共享整个进程的虚拟地址空间,包括代码、数据、堆和共享库以及打开的文件。

线程的生命周期

每个进程一开始都是由单一主线程构成的,在某一时刻,主线程创建一个对等线程,从这个时间点开始,两个线程就开始并发地运行。最后,因为主线程执行一个慢速系统调用,例如read函数或者sleep函数,线程就会被内核挂起,控制就会通过上下文切换传递到对等线程。对等线程就这样交替执行,以此类推。

并发服务器代码实现 
//本程序是基于多线程的并发服务器
//为了避免赋值语句在accept之后才完成的,那么对等线程中的局部变量connfd就得到下一次连接的描述符值,不幸的是,两个线程在同一个描述符上执行输入和输出
//为了避免这种致命竞争,必须将每个accept返回的已连接符分配到它自己的动态分配的存储器块
#include "csapp.h"



void echo(int connfd)
{
        int n;
        char buf[MAXLINE];
        rio_t rio;

        rio_readinitb(&rio,connfd);
        //带缓冲的读取函数
        while((n=rio_readlineb(&rio,buf,MAXLINE))>0) {
                //向连接符写入内容
                printf("server received %d bytes \n",n);
                rio_writen(connfd,buf,n);
        }
}


void *thread(void *vargp); //线程函数声明

//主函数入口
int main(int argc,char **argv)
{
    int listenfd,*connfd,port; //监听描述符,连接符,端口号
    socklen_t clientlen=sizeof(struct sockaddr_in); //客户端地址长度
    struct sockaddr_in clientaddr; //新建客户端地址
    pthread_t tid; //线程id
    if(argc!=2) {
        fprintf(stderr,"usage :%s <port>\n",argv[0]); //提示执行格式
        exit(0); //正常退出主程序,主进程
    }

    port=atoi(argv[1]); //把端口号转成整型
    listenfd=open_listenfd(port); //打开监听端口号
    while(1) { //无限循环,等待接受请求
        connfd=malloc(sizeof(int)); //动态分配内存给连接描述符,这是为了避免两个线程在同一个描述符上输入输出,导致两个线程在同一个描述符上的不正当竞争
        *connfd=accept(listenfd,(SA *)&clientaddr,&clientlen); //接受请求,已连接描述符
        pthread_create(&tid,NULL,thread,connfd); //新建线程,并且传递参数connfdp进入线程
    }
}

void *thread(void *vargp)
{
    int connfd=*((int *)vargp);//接受参数
    pthread_detach(pthread_self()); //分离线程,使得它不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放
    free(vargp); //释放参数存储空间
    echo(connfd); //回应客户端
    close(connfd); //关闭已连接描述符,这里不用在主线程中关闭,因为线程共享同一虚拟地址空间,此处关闭即可
    return NULL;//线程结束
}
   

上面的多线程编译时,要加上-pthread参数,程序运行如下:

zzw@zzw-ThinkPad-Edge-E430c:~$ telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
hello



zzw@zzw-ThinkPad-Edge-E430c:~/doc_main/CProgram/Concurrency$ ./echoservert.o  9999
server received 7 bytes




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值