基于C++的Linux高性能服务器1

7 篇文章 0 订阅
本文介绍了使用C++在Linux上建立一个基于TCP的高性能服务器的过程,涉及套接字编程,包括socket创建、bind、listen和accept等关键步骤。同时,文章提到了客户端的连接和数据交互,以及错误处理机制。
摘要由CSDN通过智能技术生成

开个新坑,基于C++的Linux高性能服务器,跟着教程来的,有些地方能用模板或者啥优化之类的也会试着用一用。

谈到网络编程肯定离不开套接字(socket),套接字是网络中不同主机的应用进程之间进行双向通信的端口,通俗点来讲就是两个房子之间的门,通过这个门可以进出(收发消息),进行通信。

在Linux系统中一切皆文件,统一用文件描述符来代表一个文件,而socket也不例外,也是用文件来表示的,windows下也有相似的概念,叫句柄,通过句柄也可以操作对应的文件或者进程。

接下来就是建立一个简单的服务器,各个函数介绍都在注释里,不再赘述。

由于客户端和服务器端需要使用共同的工具函数,所以干脆把工具函数单独弄到头文件里。

#include "/home/sakura/c++/Utils/utils.h"

int main() {
    //建立套接字
    //第一个参数为IP地址类型,AF_INET使用IPV4,AF_INET6使用IPV6
    //第二个参数为数据传输方式,SOCK_STREAM表示流格式,多用于TCP,SOCK_DGRAM表示数据包格式,用于UDP
    //第三个参数,协议,设置为0表示根据根据前两个参数自动推导,有TCP和UDP两种协议.
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    //创建通用套接字地址结构体,通过bzero初始化
    //sockaddr_in结构体内部有地址族,IP地址,端口和一个未使用参数,多用于保存信息然后转化为
    //sockaddr结构体使用,因为后者IP与端口放在一起储存,有的时候使用不方便.两者大小一样,可以互相转化.
    struct sockaddr_in serv_addr;
    //初始化该结构体为0
    bzero(&serv_addr, sizeof(serv_addr));

    //设置地址族,ip地址和端口
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    //将socket与文件描述符绑定
    //errif为错误处理函数
    errif(bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket bind error");

    //监听socket端口,第二个参数为最大监听队列,SOMAXCONN为128
    errif(listen(sockfd, SOMAXCONN) == -1, "socket listen error");

    //使用accpet保存客户端socket信息,比bind多一个参数socklen_t,因为需要写入客户端socket的长度
    //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);
    errif(clnt_sockfd == -1, "socket accept error");
    printf("new client fd %d! IP:%s Port:%d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr),
            ntohs(clnt_addr.sin_port));
    
    //无限循环,接受信息
    while (true) {
        //建立缓冲区
        char buf[1024];
        bzero(&buf, sizeof(buf));
        //从客户端读取数据
        ssize_t read_bytes = read(clnt_sockfd, buf ,sizeof(buf));
        //大于0, 有信息发送过来, 使用write写回
        if (read_bytes > 0) {
            printf("message from client fd %d: %s\n", clnt_sockfd, buf);
            write(clnt_sockfd, buf, sizeof(buf));
        //读取到了EOF, 一般为对方关闭socket的写端或直接close
        } else if (read_bytes == 0) {
            printf("client fd %d disconnected", clnt_sockfd);
        //-1, 发生错误
        } else if (read_bytes == -1) {
            close(clnt_sockfd);
            errif(true, "socket read error");
        } 
    }
    return 0;
}

客户端代码:

#include "/home/sakura/c++/Utils/utils.h"

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);
    errif(connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1, "socket connect error");

    while (true) {
        //建立缓冲区
        char buf[1024];
        bzero(&buf, sizeof(buf));
        //读取键盘输入
        scanf("%s", buf);
        //向服务器端发送数据
        ssize_t write_bytes = write(sockfd, buf ,sizeof(buf));

        if (write_bytes == -1) {
            printf("socket already disconnected, can't write any more");
            break;
        }
        bzero(&buf, sizeof(buf));
        ssize_t read_bytes = read(sockfd, buf ,sizeof(buf));
        //大于0, 接受到服务器返回信息
        if (read_bytes > 0) {
            printf("message from server: %s\n", buf);
        //读取到了EOF, 一般为对方关闭socket的写端或直接close
        } else if (read_bytes == 0) {
            printf("server socket disconnected");
        //-1, 发生错误
        } else if (read_bytes == -1) {
            close(sockfd);
            errif(true, "socket read error");
        } 
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值