C++Linux服务器学习之路——1

本文介绍了C++在Linux环境下开发服务器时使用epoll进行多路复用的基本原理和流程。首先解释了socket接口在操作系统中的作用,接着通过创建、绑定和监听套接字来建立服务器。然后,文章深入探讨了epoll的工作机制,包括红黑树的使用和就绪列表的概念,阐述了epoll相对于select和poll的优势。最后,提供了简单的epoll使用示例代码。
摘要由CSDN通过智能技术生成

前言:为了让所学的计网知识融合于实际,让操作系统里的理论去满足工程需求,故通过借鉴30dayMakeServer的路线以及进行相应知识点的学习。

part1
首先我们要理解socket
在这里插入图片描述
为应用层和传输层提供应用编程接口(API)。

在这里插入图片描述
同层功能协议是水平交流,实际是
在这里插入图片描述
信息传输的时候是需要一个接口去完成对应信息的转换和传输,这里我们用的那个接口就是在Linux系统下使用的socket。

引入的头文件是

#include <sys/socket.h>

其中

socket(AF_INET, SOCK_STREAM, 0)

这三个参数含义分别为:

  • 第一个参数:IP地址类型,AF_INET表示使用IPv4,如果使用IPv6请使用AF_INET6。
  • 第二个参数:数据传输方式,SOCK_STREAM表示流格式、面向连接,多用于TCP。SOCK_DGRAM表示数据报格式、无连接,多用于UDP。
  • 第三个参数:协议,0表示根据前面的两个参数自动推导协议类型。设置为IPPROTO_TCP和IPPTOTO_UDP,分别表示TCP和UDP。

每一个服务器都应该有一个唯一的标识符,而客户端要与其建立联系及传输信息,就要和这个标识符进行连接,
这个标识符由IP地址和网络端口组成,
客户端首先建立了socket这个应用编程接口,接下来要确定这个接口具体的连接对象的位置,这里我们使用

#include <arpa/inet.h>  //这个头文件包含了<netinet/in.h>

这个头文件的,

在这里插入图片描述
这个结构体有三个子对象,

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(8888);

分别是设置地址族、IP地址和端口。

因为一个服务器的端口不应该只能提供给一个客户端,所以要将这个端口变成都可访问。

这里使用了一个函数,对socket这个接口进行泛化。

bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));

有接口,并且都能让其他客户端去连接,接下来在服务器端就要加一个监听函数,来的确认运气情况。
listen函数监听这个socket端口,这个函数的第二个参数是listen函数的最大监听队列长度,系统建议的最大值SOMAXCONN被定义为128。

listen(sockfd, SOMAXCONN);

要接受一个客户端连接,需要使用accept函数。对于每一个客户端,我们在接受连接时也需要保存客户端的socket地址信息,于是有以下代码:

struct sockaddr_in clnt_addr;
socklen_t clnt_addr_len = sizeof(clnt_addr);
bzero(&clnt_addr, sizeof(clnt_addr));
int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));

要注意和acceptbind的第三个参数有一点区别,对于bind只需要传入serv_addr的大小即可,而accept需要写入客户端socket长度,所以需要定义一个类型为socklen_t的变量,并传入这个变量的地址。另外,accept函数会阻塞当前程序,直到有一个客户端socket被接受后程序才会往下运行。

客户端的写法和服务器很相似,但实现功能不同,是有点不一样的地方,在建立好接口以及绑定之后,是不需要泛化接口,之后就通过一个函数使它和服务器端连接。

connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));  

这幅图就是服务器和客户端信息交换的流程图。
在这里插入图片描述
附上的代码是来自30dayMakeServer。
其GitHub地址:
https://github.com/yuesong-feng/30dayMakeCppServer
server部分:

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

int main() {
   
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);//ip4/6 ,udp/tcp,0/??

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));//功能:置字节字符串s的前n个字节为零且包括‘\0’。
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));//第二个参数是一个指向特定协议的地址结构的指针,第三个参数是该地址结构的长度。对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以都不指定。

    listen(sockfd, SOMAXCONN);//第二个参数是一个指向特定协议的地址结构的指针,第三个参数是该地址结构的长度。对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以都不指定。
    
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_len = sizeof(clnt_addr);
    bzero(&clnt_addr, sizeof(clnt_addr));

    int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);//要接受一个客户端连接,需要使用`accept`函数。对于每一个客户端,我们在接受连接时也需要保存客户端的socket地址信息

    printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值