如何不使用任何模型裸建服务器

裸建服务器的问题较多,但是作为后端程序员依然有必要了解,以便更深刻地理解为什么要使用IO多路复用模型、异步模型等。

前导知识

网络IO:在计算机网络中进行数据的输入/输出(Input/Output)的操作,可以是由本地程序发送给本地程序,也可以是由多台不同主机上的程序进行操作。

网络IO的步骤:1、建立连接。2、接收数据(I)/准备数据(O)。3、数据处理(I)/发送数据(O)。

IP与网卡:网卡是接收数据的硬件设备。一台主机可能有多张网卡,一张网卡一般对应一个IP地址。IP地址127.0.0.1,一般用于同一张网卡之间内部进行IO。IP地址为0.0.0.0,一般表示本机所有的网卡的IP的集合。IP地址为非127.0.0.1,非0.0.0.0,一般是某张网卡的IP。

建立服务端——基于TCP协议

建立一个发送什么什么,就会返回什么数据的服务端。

建立服务端套接字

首先需要建立套接字。这个套接字有什么作用呢?打个比方,一个客户要和服务中心建立通信关系,那么客户先给这个“服务端套接字”发送消息说“我想和服务中心建立通信”,这个“服务端套接字”走了一下流程,发现没问题,于是就允许二者建立他们的通信线路。

int socket(int domain, int type, int protocol);第一个参数表示地址族,第二个参数表示套接字类型(一般决定是tcp协议还是udp协议),第三个参数通常是0,表示根据第二个套接字自动选择协议。

如何不使用任何模型裸建服务器_第1张图片

设置服务端套接字的信息

我们一般先把信息存储在一个结构体实例中,然后通过再把这个结构体实例通过bind函数绑定给套接字。如果是ipv4地址用struct sockaddr_in,如果是ipv6地址用struct sockaddr_in6。INADDR_ANY表示0.0.0.0这个IP。套接字一般分为两部分,一部分在用户空间,一部分在内核空间。在用户空间体现为一个数字,一个文件标识符,在内核空间被实现为一个结构体,用于管理网络通信的底层细节。

如何不使用任何模型裸建服务器_第2张图片

把套接字信息与套接字绑定

成功返回0,失败返回-1。

让套接字进入监听状态

第二个参数表示等待队列的长度,也就是最多能同时监听多少个来自客户端的接入请求。在等待队列中的监听请求已经进入了被监听状态,但是流程未走完。

客户端发起连接请求

推荐一个客户端连接工具:TCP/UDP Net Assistant

建立连接是不需要代码显式参与的。

在服务端用linux命令查看连接成功与否

可以看到服务端的监听端口有两个状态,一个是LISTEN,一个是ESTABLISHD。ESTABILISHD那一行记录了客户端的IP和port。

服务端接收数据

网络连接建立成功之后,服务端已经能接受信息了。但是还需要专门的操作把消息读取出来。

首先需要建立一个新的套接字,把客户端与服务端套接字的通信,转移到另一个套接字上去,并实现专门的接受报文的功能。

建立一个结构体,用于存储客户端的相关信息,比如IP,port等。补充:clientid是在stdin,stdout,stderr,socketfd的基础上依次增加的。

然后就调用recv函数通过新的套接字接收数据了。需要先准备好一块接受数据的空间。如果没有数据发送,会被阻塞住。

     

返回值是接收到的数据的长度。

发送接收到的数据

sned函数第二个参数是发送的数据的长度。如果buffer数据没准备好会被阻塞住。

clientfd的回收

查看连接的状态,刚调用close的时候,连接先进入timewait状态,因为服务端可能需要一些时间处理未完的数据,等待一段时间后会彻底关闭连接。

如果服务端出现了大量的timewait,原因大概率是服务端因为某些原因崩溃、不运行等,与大部分甚至所有客户端进行断开操作。当然,也有可能是主动断开。

用循环改进服务端——能持续接受并返回一个客户端的报文

上一版的代码是只能一次性接受并发回数据,将数据处理这部分改为while循环,可实现能持续接收并返回一个客户端的报文。

如何不使用任何模型裸建服务器_第3张图片

但是上述改进有一个问题:如果断开了连接,没办法进行close(fd)。因此需要加一个判断,判断客户端断开了连接,并跳出循环,进行close操作。

如何不使用任何模型裸建服务器_第4张图片

如果客户端已经断开了连接,但是close操作被阻塞住,那么tcp连接会进入close_wait状态。Close wait状态下客户端能重连接,但是服务端没法再进行数据处理了。

插图

用多线程改进服务端——能持续接收并返回多个客户端的报文

如何不使用任何模型裸建服务器_第5张图片

如何不使用任何模型裸建服务器_第6张图片

来一个连接,就建立一个线程进行处理。

因此,如果有1w个,就建立1w个线程。会非常地不利于大量并发。也就是传说中C10K的问题。

基于上述原因,建议服务端使用一些模型。

你可能感兴趣的:(服务器,网络,运维)