【学习记录】简单的Server端服务器模型的搭建【网络编程学习阶段汇总】

本文记录了一次简单的服务器端模型搭建的过程,涉及套接字框架、端口重用、并发多进程及IO复用等关键步骤。在服务器设计中,通过设置套接字、bind、listen、accept实现基础通信,利用端口重用解决TIME_WAIT状态问题,以提高服务重启效率。同时,讨论了并发多进程的局限,引出IO复用作为提高并发能力的解决方案。
摘要由CSDN通过智能技术生成

前一阵子想写一个服务器,嗯,一开始是想写一个电商平台来着.............

然后就开始学,慢慢的觉得自己需要学习的东西真的还有很多很多,比如用长连接还是短连接,长连接的话怎么节省系统开销,心跳包的设置,避免产生大量小包的nagle算法,html的token怎么用,还有cookie,io复用,计时器,数不清的内部算法........So,坐下来学!

然后前天写出了这个服务器的基本的样子,昨天调试时候把bug改了改,于是一个基本模型算是出来了(嗯一个没写计时器的破模型.......最近打算把计时器写一写)。

下面写一下我的学习过程。


套接字框架

首先编程中通信的基本是使用套接字。套接字分为客户端和服务端。

服务端常见的流程是socket() ->bind() ->listen() ->accept()这几个函数。

(当然也有例外,比如有一种方法是客户端进行bind之后connect,这里暂时不谈。)



socket函数

socket函数指定地址描述,套接字类型,指定协议并返回一个描述符。地址描述一般来说只能选择使用AF_INET;套接字类型有tcp,udp和原始套接字比较常用,这里我使用了tcp协议,所以参数是SOCK_STREAM;最后一个参数可以不设置,我直接将其置为0。


bind函数

bind函数将刚才返回的文件描述符绑定在一个端口。并设置一个sockaddr_in变量存储服务器本身的IP和端口等信息。


listen函数

listen函数对刚才绑定的端口进行监听,并设置一个队列长度。该队列长度事实上在内核中控制了两个队列,分别是未连接队列和已连接队列。未连接队列储存的是已经发送连接请求,但是尚未完成三次握手的客户连接,当该队列中的连接完成三次握手之后,将进入已连接队列的尾部;已连接队列储存的是已经完成三次握手但是尚未被accept函数接收的客户连接。


accept函数

accept函数从已连接队列队首获取连接,将该连接的对端信息(IP和端口等)储存在一个sockaddr_in变量中,并返回一个描述符(此次客户连接的描述符)。


端口重用

作为一个服务器,当然不能随意ctl+c掉,但是如果服务被关闭(比如服务器崩了)之后,立即重新启动服务,会出现一个无法绑定端口的错误。这是因为刚才的端口处在了TIME_WAIT的状态,内核中该状态将会维护两个MSL(maximum segment lifetime)的时间,linux下大约是1分钟左右,在此期间该端口不可再次绑定。

但是我们是服务器,关闭后重启的每一秒钟都很紧迫,所以当然不能让内核白白浪费这两个MSL的时间。所以我们使用setsockopt函数,对其设置端口重用。设置之后,该端口将立即可以重用。

具体方法:

setsockopt()函数有5个参数:分别是描述符,套接字接口类型,选项名称,选项值和选项名称。

我们重点关注前三个:

第一个:描述符,就是socket时候创建的那个描述符,服务描述符。

第二个:套接字接口类型,看下面这个表格:

套接字接口类型
SOL_SOCKET 基本套接口
IPPROTO_IP  IPv4套接口
IPPROTO_IPV6 IPv6套接口
IPPROTO_TCP TCP套接口

我们这里使用SOL_SOCKET参数。

第三个:选项名称。这个是重点,此参数有很多选项,我们使用参数SO_REUSEADDR,也就是端口重用(好吧翻译过来是地址重用,不过不要在意这个翻译了~)。

然后第四个和第五个,指向变量的指针和该指针的空间长度,我直接设置的NULL和1。


并发多进程

当然了作为一个服务器,不可能只有一个客户端来连你,所以我们要处理一些并发的访问。
最简单的办法就是使用fork函数对每个客户连接都创建一个进程。
客户进程关闭服务描述符,只处理客户描述符;
服务进程则关闭刚刚的客户描述符连接,只监听连接请求。
如下图:
/*伪代码*/

listen(listen_fd, MAX_QUEUE);
while(1)
{
	client_fd = accpet(listen_fd, client_addr, sizeof(	sockaddr_in));
	//客户连接进程
	fi( fork() == 0)
	{
		close(listen_fd);
		while( client_request(client_fd) );
		close(client);
	}
	//服务器进程
	else
		close(client_fd);

}

当然了这种架构的缺点也很明显:每个客户连接都需要分配一个独立的进程,系统开销太大&#x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值