以下为本人的学习记录,写这些文章目的为做笔记,加深记忆,并未整理订正为专业教学交流内容,所以结构有些混乱,思路比较跳跃,内容也都是自己的理解,不一定正确。若你不经意间发现了这篇文章,如果您有耐心的话,可以给我一些建议或者指出文章的问题(无论是哪个方面)。
感谢!!
这几天来重心一直放在网络编程上,对这一系列的知识点都太陌生了,每当学习新内容时,便会牵扯出更多的新内容,我只能东添西补,一会学这,一会学那。连续这样几天后,总算是摸清楚了一些套路。
对于程序员而言,网络编程,实际上就是利用操作系统给的API,在应用层进行编程,让后API将指令传给操作系统,让其进行运输层,网络层,物理层的打包,最终传输到目的地。
首先,我们的程序可能在不同的系统上运行,例如:
服务器端一般在Linux系统上运行,客户端在其他系统上运行,目前我的首要任务是Linux下服务器的搭建。
有如下一些概念需要理清楚:
socket套接字,当我们初始化一个套接字后,能得到一个文件描述符fd,通过管理文件描述符来管理这个抽象的socket,我们能对socket做这些操作:bind将socket绑定到一个端口上,sockaddr为包含ip和端口信息的一种数据结构,listen利用socket监听绑定的端口,accept接受监听到达请求信息并得到对方的信息,还有connect连接,读写收发,close关闭socket等。有了这些函数,我们便能实现最基础的通信。
但服务器端一个端口应当能接受多个客户端,为了达到这个目的,我们或许想出这种方法
方法1:排队依次处理
在main函数中,不断的循环调用accept函数接受客户端的请求,但这种方式有问题,就是客户端必须排队,等到前面的客户端working结束后才能连接。
while(1)
{
int rfd=accept();
working(rfd);
}
举个例子,普通打印店:
只有一台打印机,要想打印则必须排队,流程如下
1、去打印店,然后排上队。
去打印店申请打印相当于客户端发起connect请求,排上队相当于进入了监听端口的队列中
2、轮到你时,打印店老板同意让你打印,并让你使用打印机。
打印店老板同意相当于服务器端accept你的请求了
让你使用打印机,相当于开始处理你的需求。
3、你取走文档,打印机空闲,等待下一个用户。
这种方式,每个人都需要等待前面的人打印完成之后才能使用打印机
不符合服务器支持多个用户同时使用的需求。
方法2:多线程处理
多线程处理,在main函数中循环accept,收到连接请求后,便创建一个新线程,把用于通信的文件描述符,和处理这个通信的工作函数传进去,在新的线程中处理客户端的需求。
while(1)
{
int rfd=accept();
创建线程(rfd,工作函数);
}
依然以打印店举例
这时打印店,最初只有一台打印机
1、你准备好你的文档,来到打印店;
2、请求打印
3、不需要排队了,只要你发出请求,老板就创建一个打印机给你用
4、你获得打印机使用权了,开始打印;
5、打印完成,老板便将打印机销毁
相当于只要客户端发出connect请求,服务器便accept,并为客户端创建一个线程供其使用,使用完毕之后再将线程销毁。
但这样有个问题,需要频繁的创建销毁线程,消耗很多资源。
于是针对这个方案进行优化:
方法2升级版:线程池处理
在一开始就创建一个线程池,在里面放入适量的线程,每当有客户端请求时,我便把线程分给他用。若客户端太多,导致线程池不够用了,便再创建一些线程添加到线程池中,用完之后再销毁。这样便能减少创建线程和销毁线程的开销。
注意:线程池中线程的创建和销毁是一对应的算法控制的,保证线程够用,且节约资源
while (1)
{
struct myip* pinfo = new myip();
pinfo->fd = accept(lfd, (struct sockaddr*)&pinfo->addr, (socklen_t*)&clilen);
if (pinfo->fd == -1)
{
perror("accept");
continue;
}
add_task(pool,request_handler , pinfo);
}
这时打印店,最初便有多台打印机
1、你准备好你的文档,来到打印店;
2、请求打印
3、不需要排队了,只要你发出请求,老板就分配一台打印机给你用,如果没有空闲的打印机,就创建一个打印机加入到店铺中,给你使用
4、你获得打印机使用权了,开始打印;
5、打印完成,打印机回归空闲
方法3:Linux的epoll模型
此时打印店只有一台打印机,你只要排上队,老板便会管理你的请求
(相当于connect被accept,那你的业务就归epoll管了)
1、告诉老板说,我先排队在这位置,轮到我了通知一声(假定你来回路上不耗时);
2、你先去忙你的事情去了;
3、轮到你了,店小二通知你(假定你来回路上不耗时);
4、你获得打印机使用权了,开始打印;
5、打印完了拿走。
你会发现,你节省了排队的时间,等到你能获得打印机资源的时候,告诉你来处理。但是这里,就浪费了一点时间,就是你自己打印。这就是epoll的同步非阻塞。
方法4:windows的IOCP模型
1、你准备好你的文档,来到打印店;
2、告诉店小二说,我先排队,轮到我了帮打印下,好了通知我(也假定你来回路上不耗时);
3、你先去忙你的事情去了;
4、轮到你的文档了,店小二直接帮你打印好了,通知你;
5、你来了,直接取走文档。