您当前的位置:首页 > 问答 > 内容

一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

关于【一分钟笑掉大牙】,一分钟笑掉大牙的幽默段子,今天涌涌小编给您分享一下,如果对您有所帮助别忘了关注本站哦。

内容导航:1、从0实现基于Linux socket聊天室-多线程服务器模型-12、一分钟笑掉大牙的幽默段子

1、从0实现基于Linux socket聊天室-多线程服务器模型-1

Socket在实际系统程序开发张中,应用非常广泛,也非常重要。实际应用中服务器经常需要支持多个客户端连接,实现高并发服务器模型显得尤为重要。高并发服务器从简单的循环服务器模型处理少量网络并发请求,演进到解决C10K,C10M问题的高并发服务器模型。

C/S架构

服务器-客户机,即Client-Server(C/S)结构。C/S结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。

在C/S结构中,应用程序分为两部分:服务器部分和客户机部分。服务器部分是多个用户共享的信息与功能,执行后台服务,如控制共享数据库的操作等;客户机部分为用户所专有,负责执行前台功能,在出错提示、在线帮助等方面都有强大的功能,并且可以在子程序间自由切换。一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)如上图所示:这是基于套接字实现客户端和服务器相连的函数调用关系,socket API资料比较多,本文不再过多叙述。

pthread线程库:(POSIX)

pthread线程库是Linux下比较常用的一个线程库,关于他的用法和特性大家可以自行搜索相关文章,下面只简单介绍他的用法和编译。

线程标识

线程有ID, 但不是系统唯一, 而是进程环境中唯一有效.线程的句柄是pthread_t类型, 该类型不能作为整数处理, 而是一个结构.下面介绍两个函数:

头文件:<pthread.h>原型:intpthread_equal(pthread_ttid1,pthread_ttid2);返回值:相等返回非0,不相等返回0.说明:比较两个线程ID是否相等.头文件:<pthread.h>原型:pthread_tpthread_self();返回值:返回调用线程的线程ID.

线程创建

在执行中创建一个线程, 可以为该线程分配它需要做的工作(线程执行函数), 该线程共享进程的资源. 创建线程的函数pthread_create()

头文件:<pthread.h>原型:intpthread_create(pthread_t*restricttidp,constpthread_attr_t*restrictattr,void*(start_rtn)(void),void*restrictarg);返回值:成功则返回0,否则返回错误编号.参数:tidp:指向新创建线程ID的变量,作为函数的输出.attr:用于定制各种不同的线程属性,NULL为默认属性(见下).start_rtn:函数指针,为线程开始执行的函数名.该函数可以返回一个void*类型的返回值,而这个返回值也可以是其他类型,并由pthread_join()获取arg:函数的唯一无类型(void)指针参数,如要传多个参数,可以用结构封装.

编译

因为pthread的库不是linux系统的库,所以在进行编译的时候要加上-lpthread#gccfilename-lpthread//默认情况下gcc使用c库,要使用额外的库要这样选择使用的库

常见的网络服务器模型

本文结合自己的理解,主要以TCP为例,总结了几种常见的网络服务器模型的实现方式,并最终实现一个简单的命令行聊天室。

单进程循环

单线进程循环原理就是主进程没和客户端通信,客户端都要先连接服务器,服务器接受一个客户端连接后从客户端读取数据,然后处理并将处理的结果返还给客户端,然后再接受下一个客户端的连接请求。

优点

单线程循环模型优点是简单、易于实现,没有同步、加锁这些麻烦事,也没有这些开销。

缺点

阻塞模型,网络请求串行处理;

没有利用多核cpu的优势,网络请求串行处理;

无法支持同时多个客户端连接;

程序串行操作,服务器无法实现同时收发数据。一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

单线程IO复用

linux高并发服务器中常用epoll作为IO复用机制。线程将需要处理的socket读写事件都注册到epoll中,当有网络IO发生时,epoll_wait返回,线程检查并处理到来socket上的请求。

优点

实现简单, 减少锁开销,减少线程切换开销。

缺点

只能使用单核cpu,handle时间过长会导致整个服务挂死;

当有客户端数量超过一定数量后,性能会显著下降;

只适用高IO、低计算,handle处理时间短的场景。

一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

多线程/多进程

多线程、多进程模型主要特点是每个网络请求由一个进程/线程处理,线程内部使用阻塞式系统调用,在线程的职能划分上,可以由一个单独的线程处理accept连接,其余线程处理具体的网络请求(收包,处理,发包);还可以多个进程单独listen、accept网络连接。

优点:

1、实现相对简单;

2、利用到CPU多核资源。

缺点:

1、线程内部还是阻塞的,举个极端的例子,如果一个线程在handle的业务逻辑中sleep了,这个线程也就挂住了。一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

多线程/多进程IO复用

多线程、多进程IO服用模型,每个子进程都监听服务,并且都使用epoll机制来处理进程的网络请求,子进程 accept() 后将创建已连接描述符,然后通过已连接描述符来与客户端通信。该机制适用于高并发的场景。

优点:

支撑较高并发。

缺点:

异步编程不直观、容易出错

一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

多线程划分IO角色

多线程划分IO角色主要功能有:一个accept thread处理新连接建立;一个IO thread pool处理网络IO;一个handle thread pool处理业务逻辑。使用场景如:电销应用,thrift TThreadedSelectorServer。

优点:

按不同功能划分线程,各线程处理固定功能,效率更高

可以根据业务特点配置线程数量来性能调优

缺点:

线程间通信需要引入锁开销

逻辑较复杂,实现难度大

一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

小结

上面介绍了常见的网络服务器模型,还有AIO、协程,甚至还有其他的变型,在这里不再讨论。重要的是理解每种场景中所面临的问题和每种模型的特点,设计出符合应用场景的方案才是好方案。

多线程并发服务器模型

下面我们主要讨论多线程并发服务器模型。

代码结构

并发服务器代码结构如下:

thread_func(){while(1){recv(...);process(...);send(...);}close(...);}main(socket(...);bind(...);listen(...);while(1){accept(...);pthread_create();}}

由上可以看出,服务器分为两部分:主线程、子线程。

主线程

main函数即主线程,它的主要任务如下:

socket()创建监听套字;

bind()绑定端口号和地址;

listen()开启监听;

accept()等待客户端的连接,

当有客户端连接时,accept()会创建一个新的套接字new_fd;

主线程会创建子线程,并将new_fd传递给子线程。

子线程

子线程函数为thread_func(),他通过new_fd处理和客户端所有的通信任务。

客户端连接服务器详细步骤

下面我们分步骤来看客户端连接服务器的分步说明。

1. 客户端连接服务器

服务器建立起监听套接字listen_fd,并初始化;

客户端创建套接字fd1;

客户端client1通过套接字fd1连接服务器的listen_fd;

一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

2. 主线程创建子线程thread1

server收到client1的连接请求后,accpet函数会返回一个新的套接字newfd1;

后面server与client1的通信就依赖newfd1,监听套接字listen_fd会继续监听其他客户端的连接;

主线程通过pthead_create()创建一个子线程thread1,并把newfd1传递给thread1;

server与client1的通信就分别依赖newfd1、fd1。

client1为了能够实时收到server发送的信息,同时还要能够从键盘上读取数据,这两个操作都是阻塞的,没有数据的时候进程会休眠,所以必须创建子线程read_thread;

client1的主线负责从键盘上读取数据并发送给,子线程read_thread负责从server接受信息。

一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

3. client2连接服务器

客户端client2创建套接字fd2;

通过connect函数连接server的listen_fd;一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

4. 主线程创建子线程thread2

server收到client2的连接请求后,accpet函数会返回一个新的套接字newfd2;

后面server与client2的通信就依赖newfd2,监听套接字listen_fd会继续监听其他客户端的连接;

主线程通过pthead_create()创建一个子线程thread2,并把newfd2传递给thread2;

server与client1的通信就分别依赖newfd2、fd2。

同样client2为了能够实时收到server发送的信息,同时还要能够从键盘上读取数据必须创建子线程read_thread;

client1的主线负责从键盘上读取数据并发送给,子线程read_thread负责从server接受信息。

一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)在这里插入图片描述

由上图可见,每一个客户端连接server后,server都要创建一个专门的thread负责和该客户端的通信;每一个客户端和server都有一对固定的fd组合用于连接。

实例

好了,理论讲完了,根据一口君的惯例,也继承祖师爷的教诲:talk is cheap,show you my code.不上代码,只写理论的文章都是在耍流氓。

本例的主要功能描述如下:

实现多个客户端可以同时连接服务器;

客户端可以实现独立的收发数据;

客户端发送数据给服务器后,服务器会将数据原封不动返回给客户端。

服务器端

/*********************************************服务器程序TCPServer.c公众号:一口Linux*********************************************/#include<stdio.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<errno.h>#include<string.h>#include<pthread.h>#include<stdlib.h>#defineRECVBUFSIZE2048void*rec_func(void*arg){intsockfd,new_fd,nbytes;charbuffer[RECVBUFSIZE];inti;new_fd=*((int*)arg);free(arg);while(1){if((nbytes=recv(new_fd,buffer,RECVBUFSIZE,0))==-1){fprintf(stderr,"ReadError:%s\n",strerror(errno));exit(1);}if(nbytes==-1){//客户端出错了返回值-1close(new_fd);break;}if(nbytes==0){//客户端主动断开连接,返回值是0close(new_fd);break;}buffer[nbytes]='\0';printf("Ihavereceived:%s\n",buffer);if(send(new_fd,buffer,strlen(buffer),0)==-1){fprintf(stderr,"WriteError:%s\n",strerror(errno));exit(1);}}}intmain(intargc,char*argv[]){charbuffer[RECVBUFSIZE];intsockfd,new_fd,nbytes;structsockaddr_inserver_addr;structsockaddr_inclient_addr;intsin_size,portnumber;charhello[]="Hello!Socketcommunicationworld!\n";pthread_ttid;int*pconnsocke=NULL;intret,i;if(argc!=2){fprintf(stderr,"Usage:%sportnumber\a\n",argv[0]);exit(1);}if((portnumber=atoi(argv[1]))<0){fprintf(stderr,"Usage:%sportnumber\a\n",argv[0]);exit(1);}if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){fprintf(stderr,"Socketerror:%s\n\a",strerror(errno));exit(1);}bzero(&server_addr,sizeof(structsockaddr_in));server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//自动获取网卡地址server_addr.sin_port=htons(portnumber);if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1){fprintf(stderr,"Binderror:%s\n\a",strerror(errno));exit(1);}if(listen(sockfd,10)==-1){fprintf(stderr,"Listenerror:%s\n\a",strerror(errno));exit(1);}while(1){sin_size=sizeof(structsockaddr_in);if((new_fd=accept(sockfd,(structsockaddr*)&client_addr,&sin_size))==-1){fprintf(stderr,"Accepterror:%s\n\a",strerror(errno));exit(1);}pconnsocke=(int*)malloc(sizeof(int));*pconnsocke=new_fd;ret=pthread_create(&tid,NULL,rec_func,(void*)pconnsocke);if(ret<0){perror("pthread_createerr");return-1;}}//close(sockfd);exit(0);}

客户端

/*********************************************服务器程序TCPServer.c公众号:一口Linux*********************************************/#include<stdio.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<errno.h>#include<string.h>#include<pthread.h>#include<stdlib.h>#defineRECVBUFSIZE1024void*func(void*arg){intsockfd,new_fd,nbytes;charbuffer[RECVBUFSIZE];new_fd=*((int*)arg);free(arg);while(1){if((nbytes=recv(new_fd,buffer,RECVBUFSIZE,0))==-1){fprintf(stderr,"ReadError:%s\n",strerror(errno));exit(1);}buffer[nbytes]='\0';printf("Ihavereceived:%s\n",buffer);}}intmain(intargc,char*argv[]){intsockfd;charbuffer[RECVBUFSIZE];structsockaddr_inserver_addr;structhostent*host;intportnumber,nbytes;pthread_ttid;int*pconnsocke=NULL;intret;//检测参数个数if(argc!=3){fprintf(stderr,"Usage:%shostnameportnumber\a\n",argv[0]);exit(1);}//argv2存放的是端口号,读取该端口,转换成整型变量if((portnumber=atoi(argv[2]))<0){fprintf(stderr,"Usage:%shostnameportnumber\a\n",argv[0]);exit(1);}//创建一个套接子if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){fprintf(stderr,"SocketError:%s\a\n",strerror(errno));exit(1);}//填充结构体,ip和port必须是服务器的bzero(&server_addr,sizeof(server_addr));server_addr.sin_family=AF_INET;server_addr.sin_port=htons(portnumber);server_addr.sin_addr.s_addr=inet_addr(argv[1]);//argv【1】是serverip地址if(connect(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1){fprintf(stderr,"ConnectError:%s\a\n",strerror(errno));exit(1);}//创建线程pconnsocke=(int*)malloc(sizeof(int));*pconnsocke=sockfd;ret=pthread_create(&tid,NULL,func,(void*)pconnsocke);if(ret<0){perror("pthread_createerr");return-1;}while(1){#if1printf("inputmsg:");scanf("%s",buffer);if(send(sockfd,buffer,strlen(buffer),0)==-1){fprintf(stderr,"WriteError:%s\n",strerror(errno));exit(1);}#endif}close(sockfd);exit(0);}

编译

编译线程,需要用到pthread库,编译命令如下:

gcc s.c -o s -lpthread

gcc cli.c -o c -lpthread先本机测试

开启一个终端 ./s 8888

再开一个终端 ./cl 127.0.0.1 8888,输入一个字符串"qqqqqqq"

再开一个终端 ./cl 127.0.0.1 8888,输入一个字符串"yikoulinux"一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)

有读者可能会注意到,server创建子线程的时候用的是以下代码:

pconnsocke=(int*)malloc(sizeof(int));*pconnsocke=new_fd;ret=pthread_create(&tid,NULL,rec_func,(void*)pconnsocke);if(ret<0){perror("pthread_createerr");return-1;}

为什么必须要malloc一块内存专门存放这个新的套接字呢?这个是一个很隐蔽,很多新手都容易犯的错误。下一章,我会专门给大家讲解。

2、一分钟笑掉大牙的幽默段子

一分钟笑掉大牙的幽默段子

1、虽然我不会做饭,但是我点得一手好外卖呀!

2、紫薇!紫薇!你看见我的紫薇了吗?你的嘴不长在你脸上的吗?

3、如果不能一夜暴富,两夜也行,半个月我也可以接受。

4、不靠谱的不是感情,而是人!车越破,备胎也就越多!把恋爱的酸臭味忘了吧,你只需要记住钱的芳香。

5、熟练掌握如下词汇,你就能成为一个职场老油条:问题不大、我尽量、我考虑一下、有机会的话…。

6、我妈看着亲戚家的漂亮女儿对我说:“人家的脸像做过的,你的脸像坐过的!”

7、我曾在38度的高温下扬言,我宁可冻死也不愿热成狗,直到今天我被冻成狗,我才明白太美的承诺因为太年轻。

8、我国家长们的'通病,喜欢把孩子当成自己的游戏小号,大号让自己玩废了,但是觉得已经自己掌握了大部分通关秘诀,拿小号再修炼一遍就打遍天下无敌手了,岂不知游戏规则早变了……

9、你我互道晚安,却在王者峡谷相遇。

10、一同学对老师说:“老师,你教的都是没用的东西。”结果老师回答说:“我不允许你这么说自己。”

11、我以为生活就是猫吃鱼,狗吃肉,奥特曼打小怪兽。现实却是鼠整猫,羊耍狼,两熊玩死光头强。

12、老师指着上课玩手机的同学:“大家快看啊,他怎么盯着裤裆在笑”。

13、其实以前我有八块腹肌,练第九块的时候走火入魔,九九归一了。

14、会做饭,做家务,会修理电器,这些技能想闪光,一定是在特别能赚钱的衬托下。

15、“你必须给我加薪!”一个人对他的老板说,“现在有三家公司正找我呢。”“是吗?”老板问他,“是哪三家公司找你?”“电力公司、电话公司,还有煤气公司。”

一分钟笑掉大牙的幽默段子

1、有一天,网上的一个小兄弟问我改网名吗?他说他叫“鲸落南北”,猜我叫什么,果然这狗东西嘴巴里没好话,“鲨掉东西”。

2、从前有一个小老鼠,小老鼠看到一个奶酪,它想吃但是心里想:一定是陷阱!在它反复尝试周围没有异常然后觉得没有陷阱的时候,它变成了酱紫~

3、考试的时候打小抄,趁着监考老师不在的时候在书桌底下翻书,后来老师看到了说道:“同学,考的是化学,你翻物理书那么起劲干嘛?”

4、一般女生都喜欢看韩剧,男生都喜欢看日剧。但是如果没有字幕的话女生是不会看的,但如果是日剧没有字幕的话,没关系!都下载了,凑合看吧!

5、早上着急上学,赶紧穿上了衣服吃早点准备奔赴学校,老妈看到我的脚,“你袜子穿错了!”我赶紧回去换了袜子之后就上学去了。晚上回来的时候才发现我又穿错了!

6、每天都有一个女同事会早走几分钟,有一次正好碰到她就说起了这件事,问她原因,她说因为每天都有不同的车接她,她怕让人看到不好!一开始我以为是什么八卦呢,后来发现她丫的打的顺风车!

7、上学的时候一直都搞不懂一件事,就是每次老师都说我是搅屎棍,我当时就想我好歹是个棍,你们可都是……

8、刚才和女友一起去医院检查,完了之后回家她跟我说:亲爱的,告诉你一个小好消息我怀孕了~我当时就气的不行,拿出我不孕不育的报告摔在她脸上,“你tm不早说,吓死我了!”

9、同事看到我钱包里老婆的照片夸我真是个好男人,可是他不知道我这么做不是为了别的,就是提醒自己自己的钱到底是怎么没的!

一分钟笑掉大牙的幽默段子

1、虽然我不会做饭,但是我点得一手好外卖呀!

2、紫薇!紫薇!你看见我的紫薇了吗?你的嘴不长在你脸上的吗?

3、如果不能一夜暴富,两夜也行,半个月我也可以接受。

4、不靠谱的不是感情,而是人!车越破,备胎也就越多!把恋爱的酸臭味忘了吧,你只需要记住钱的芳香。

5、熟练掌握如下词汇,你就能成为一个职场老油条:问题不大、我尽量、我考虑一下、有机会的话…。

6、我妈看着亲戚家的漂亮女儿对我说:“人家的脸像做过的,你的脸像坐过的!”

7、我曾在38度的高温下扬言,我宁可冻死也不愿热成狗,直到今天我被冻成狗,我才明白太美的承诺因为太年轻。

8、我国家长们的'通病,喜欢把孩子当成自己的游戏小号,大号让自己玩废了,但是觉得已经自己掌握了大部分通关秘诀,拿小号再修炼一遍就打遍天下无敌手了,岂不知游戏规则早变了……

9、你我互道晚安,却在王者峡谷相遇。

10、一同学对老师说:“老师,你教的都是没用的东西。”结果老师回答说:“我不允许你这么说自己。”

11、我以为生活就是猫吃鱼,狗吃肉,奥特曼打小怪兽。现实却是鼠整猫,羊耍狼,两熊玩死光头强。

12、老师指着上课玩手机的同学:“大家快看啊,他怎么盯着裤裆在笑”。

13、其实以前我有八块腹肌,练第九块的时候走火入魔,九九归一了。

14、会做饭,做家务,会修理电器,这些技能想闪光,一定是在特别能赚钱的衬托下。

15、“你必须给我加薪!”一个人对他的老板说,“现在有三家公司正找我呢。”“是吗?”老板问他,“是哪三家公司找你?”“电力公司、电话公司,还有煤气公司。”

本文关键词:一分钟笑掉大牙 开心幽默笑话,最搞笑的笑话一分钟笑掉大牙,30个笑掉大牙的笑话段子,笑话大全一分钟笑掉牙,超搞笑的笑话笑掉大牙句子。这就是关于《一分钟笑掉大牙,一分钟笑掉大牙的幽默段子(socket聊天室-多线程服务器模型-1)》的所有内容,希望对您能有所帮助!


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: 刘海油得快的原因,刘海容易油怎么办(这样做就能搞定它)

下一篇: 寓意夏天出生的名字,夏天这个名字的寓意(“招弟改名”的背后……)



猜你感兴趣

推荐阅读

网站内容来自网络,如有侵权请联系我们,立即删除! | 软文发布 | 粤ICP备2021106084号