当前位置: 首页 > wzjs >正文

平面设计素材网站知乎泰州seo

平面设计素材网站知乎,泰州seo,淮北seo,运营主要做什么工作目录 设计思路 类的设计 模块的实现 基础模块 特殊模块 集成模块 主函数 主函数实现 主函数测试 疑惑点 设计思路 Socket模块主要是对套接字的基础操作进行封装,简化我们对套接字的操作,不需要调用C的原生接口,而是以面向对象的…

目录

设计思路

类的设计 

模块的实现

基础模块

特殊模块 

集成模块 

主函数

主函数实现

主函数测试

疑惑点


设计思路

Socket模块主要是对套接字的基础操作进行封装,简化我们对套接字的操作,不需要调用C的原生接口,而是以面向对象的方式来调用。 

那么我们需要封装哪些接口呢?

  • 首先,最基础的接口,创建套接字,绑定地址信息,建立连接,开始监听,获取新连接,读取数据,写入数据,关闭套接字这几个基本功能我们还是需要提供的。
  • 其次就是两个特殊的功能: 设置套接字非阻塞,因为后续我们读取和写入都是非阻塞进行的。 还有就是设置地址信息和端口号复用,这是为了便于服务器崩溃之后能够立即以固定端口重启。
  • 还需要提供两个集成的功能,创建一个服务器连接,以及建立一个客户端连接

类的设计 

public: /*-- - 基础功能-- -*/bool Create();//创建套接字bool Bind();//绑定地址信息bool Connect();//向服务端发起连接bool Listen();//服务端开始监听int Accept();//获取客户端连接ssize_t send();//发送数据ssize_t Recv();//接收数据void close();//关闭套接字/*-- - 特殊功能-- -*/ssize_t SendNonBlock(void *buf, size_t len) // 非阻塞发送数据void SetNonBlock();//设置套接字非阻塞void SetAddrReuse();//设置地址信息和端口号复用/*-- - 整合功能-- -*/bool CreateServer();//创建一个服务器连接bool CreateClient();//创建一个客户端连接
};

模块的实现

这个模块是把服务端的Socket和客户端的Socket整合到一起了

基础模块

class Socket
{
private:int _sockfd;public:Socket() // 接收监听套接字的构造函数: _sockfd(-1){}Socket(int sockfd) // 接收客户端连接后的通信套接字: _sockfd(sockfd){}~Socket() { Close(); }/*-- - 基础功能-- -*/bool Create() // 创建套接字{_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (_sockfd < 0){ERR_LOG("Create failed");return false;}std::cout << "sockfd:" << _sockfd << std::endl;return true;}bool Bind(const string &ip, uint16_t port) // 绑定地址信息{struct sockaddr_in addr;memset(&addr, 0, sizeof addr);addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(ip.c_str());addr.sin_port = htons(port);socklen_t len = sizeof addr;int n = bind(_sockfd, (struct sockaddr *)&addr, len);if (n < 0){ERR_LOG("Bind failed");return false;}std::cout << "Bind:" << n << std::endl;return true;}bool Listen(int backlog = MAX_LISTEN) // 服务端开始监听{int n = listen(_sockfd, backlog);if (n < 0){ERR_LOG("Listen failed");return false;}std::cout << "Listen:" << n << std::endl;return true;}bool Connect(const string &ip, uint16_t port) // 向服务端发起连接{struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(ip.c_str());addr.sin_port = htons(port);socklen_t len = sizeof addr;int n = connect(_sockfd, (struct sockaddr *)&addr, len);if (n < 0){ERR_LOG("Connect failed");return false;}std::cout << "Connect:" << n << std::endl;return true;}int Accept() // 获取客户端连接{int connfd = accept(_sockfd, nullptr, nullptr);std::cout << "Accept:" << connfd << std::endl;if (connfd < 0){ERR_LOG("Accept failed");return -1;}return connfd;}ssize_t Send(const void *buf, size_t len, int flag = 0) // 将数据从用户态缓冲区发送到内核缓冲区{int n = send(_sockfd, buf, len, flag);if (n < 0){if (errno == EAGAIN || errno == EINTR){return 0;ERR_LOG("send failed");return -1;}}return n;}ssize_t Recv(void *buf, size_t len, int flag = 0) // 接收数据{int n = recv(_sockfd, buf, len, flag);if (n < 0){if (errno == EAGAIN || errno == EINTR){return 0;ERR_LOG("recv failed");return -1;}}return n;}void Close() // 关闭套接字{close(_sockfd);}ssize_t SendNonBlock(void *buf, size_t len) // 非阻塞发送数据{return Recv(buf, len, MSG_DONTWAIT);}};

特殊模块 

为什么需要把套接字设置成非阻塞属性呢?

设置非阻塞其实就两个步骤,首先获取描述符当前属性,然后再在获取到的属性上加上我们的非阻塞属性,再将其设置进描述符中。 这里需要用到 fcntl() 接口 

int fcntl(int fd, int cmd, ... /* arg */);

    man手册中说明了,获取和设置O_CLOEXEC 也就是不可被拷贝,是使用 F_GETFD和F_SETFD,而其他属性的获取和设置则需要使用F_GETFL 和 F_SETFL。

        // 设置套接字非阻塞属性void SetNonBlock(){// int fcntl(int fd, int cmd, ...)int flag = fcntl(_sockfd, F_GETFL, 0);fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);}

     地址信息和端口号复用需要用到的 setsockopt()  接口

    int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
    

    第一个参数就是要设置的文件描述符或者说套接字,第二个参数就是要设置的层级,第三个参数表示要进行什么操作,第四个参数表示要设置的值,1 表示激活,0表示取消,第四个参数表示第三个参数的大小。

        void SetAddrReuse() // 设置地址信息和端口号复用{int val = 1;int ret = setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &val, sizeof val);// 设置 SO_REUSEADDR 可以绑定处于 TIME_WAIT 状态的端口// 设置 SO_REUSEPORT 可以让一个端口被多个 socket 绑定,可以用于实现负载均衡}

    集成模块 

    然后就是设计两个集成端口,首先创建服务器套接字,他需要创建一个套接字绑定端口和IP设置非阻塞,还要设置地址复用,以及开始监听。 

        bool CreateServer(uint16_t port, const string &ip = "0.0.0.0", bool nonblock = false) // 创建一个服务器连接{// 1.创建套接字 2.绑定地址 3.开始监听 4.打开地址重用 5.设置非阻塞if (Create() == false)return false;if (Bind(ip, port) == false)return false;if (Listen() == false)return false;SetAddrReuse();if (nonblock)SetNonBlock();return true;}

    而建立一个客户端套接字,他也需要创建套接字,但是它不需要我们显式绑定端口和IP,然后就是调用Conect进行连接服务器。注意客户端套接字不要connect之前设置非阻塞,因为如果设置了非阻塞,那么我们就无法判断connect是否连接成功。

        bool CreateClient(uint16_t port, const string &ip) // 创建一个客户端连接{// 1.创建套接字 2.连接客户端if (Create() == false)return false;if (Connect(ip, port) == false)return false;return true;}

    主函数

    主函数实现

    server.cc

    #include <iostream>
    #include "Socket.hpp"#define PORT 8080int main()
    {// 创建服务端套接字Socket serverSocket;// 创建并初始化服务端if (!serverSocket.CreateServer(PORT, "0.0.0.0", true)){std::cerr << "Server initialization failed!" << std::endl;return -1;}std::cout << "Server is listening on port " << PORT << "..." << std::endl;// 接受客户端连接int clientSocket = -1;while (1){sleep(1);clientSocket = serverSocket.Accept();if (clientSocket < 0){std::cerr << "Failed to accept client connection!" << std::endl;}else{break;}}std::cout << "Client connected!" << std::endl;Socket conSocket(clientSocket);int RecvCount = 5;// 接收数据while (RecvCount){char buffer[1024] = {0};ssize_t bytesReceived = conSocket.Recv(buffer, sizeof(buffer));if (bytesReceived > 0){std::cout << "Received from client: " << buffer << std::endl;RecvCount--;}else{std::cerr << "Failed to receive data from client!" << std::endl;}sleep(1);}// 发送数据到客户端int SendCount = 5;while (SendCount){const char *response = "Hello from server!";ssize_t bytesSent = conSocket.Send(response, strlen(response));if (bytesSent > 0){std::cout << "Sent to client: " << response << std::endl;SendCount--;}else{std::cerr << "Failed to send data to client!" << std::endl;}sleep(1);}// 关闭连接serverSocket.Close();std::cout << "Server closed!" << std::endl;return 0;
    }

    client.cc 

    #include <iostream>
    #include "Socket.hpp"#define PORT 8080int main()
    {// 创建客户端套接字Socket clientSocket;// 创建并初始化客户端if (!clientSocket.CreateClient(PORT, "127.0.0.1")){std::cerr << "Client initialization failed!" << std::endl;return -1;}std::cout << "Client connected to server!" << std::endl;// 发送数据到服务端int SendCount = 5;while (SendCount){const char *message = "Hello from client!";ssize_t bytesSent = clientSocket.Send(message, strlen(message));if (bytesSent > 0){std::cout << "Sent to server: " << message << std::endl;SendCount--;}else{std::cerr << "Failed to send data to server!" << std::endl;}sleep(1);}// 接收数据从服务端int RecvCount = 5;while (RecvCount){char buffer[1024] = {0};ssize_t bytesReceived = clientSocket.Recv(buffer, sizeof(buffer));if (bytesReceived > 0){std::cout << "Received from server: " << buffer << std::endl;RecvCount--;}else{std::cerr << "Failed to receive data from server!" << std::endl;}sleep(1);}// 关闭连接clientSocket.Close();std::cout << "Client closed!" << std::endl;return 0;
    }

    主函数测试

    客户端往服务端发送数据

    Client.cc

    const char *message = "Hello from client!";

    ssize_t bytesSent = clientSocket.Send(message, strlen(message));

    这两段代码的过程如下:

    Server.CC 

    char buffer[1024] = {0};

    ssize_t bytesReceived = conSocket.Recv(buffer, sizeof(buffer));

    这两段代码的过程如下:

     服务端与客户端双向发送/接收,以及关闭

    疑惑点

    关于套接字的基础功能,为啥已经建立连接了,后面又获取连接了?

    因为你建立的连接是客户端->服务端的,而获取新连接,是指的服务端获取到了客户端的连接。 

    socket函数的用法 

    int socket(int domain, int type, int protocol);
    

    这里为啥要用到memset?

    bind函数的用法 

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    

     accept的用法

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    


     

    send的用法

    send read write接口的解释

    ssize_t send(const void* buf, size_t len, int flag = 0)  这里的buf指的是内核发送缓冲区还是用户态的输出缓冲区?

    send的sockfd参数是干嘛的

    是不是意思就是说,A与B进行通信的话 会有个sockfd1 C与D进行通信的话,会有个sockfd2?

    不是的

    但是每对通信的客户端和服务端都需要独立的套接字进行数据传输 

     send发送数据

      send发送数据指的是从用户态缓冲区发送到内核态缓冲区,并不是从客户端发送到服务端了

    这里send函数为啥不传_sockfd 

     为什么会有两个构造函数

    ​ 

    send()是把数据从用户输出缓冲区发送到内核的输出缓冲区中 这个内核的输出缓冲区是指的自己的内核缓冲区 还是对端的内核缓冲区?

    为什么Accept的返回值为-1

    因为此时客户端还没连接,但已经调用了获取客户端的接口。所以会返回-1

    CTRL + Z后,再次启动bind失败

    客户端发送了数据 但是服务端收不到数据 

    ​ 

    http://www.dtcms.com/wzjs/384158.html

    相关文章:

  • 建站公司最新价格企业整站seo
  • win7系统做asp网站哪里有网站推广优化
  • 网站admin密码今日最火的新闻
  • 企业网站推广属于付费推广吗服务器ip域名解析
  • 小说网站防盗做的最好的是小程序开发软件
  • 请简述网站建设的一般流程谷歌浏览器引擎入口
  • 如何把字体导入wordpressseo+网站排名
  • 福田做商城网站建设哪家公司靠谱免费发布广告信息网
  • 网站建设费用是多少钱怎样做一个产品营销方案
  • 免费建立网站论坛青岛seo博客
  • 衡水专业网站制作微信朋友圈广告投放价格表
  • 中小学做课题研究的网站新媒体运营怎么自学
  • 网站建设与管理 教材网站搭建免费
  • 网站构造百度智能建站平台
  • 广告网站建设及推广百度竞价推广方案范文
  • 网站建设最新签约下载app到手机上并安装
  • 政府网站集约化建设情况报告看广告收益的正规平台
  • asp服装商城网站源码高端品牌网站建设
  • 制作网站的程序seo交互论坛
  • 房地产门户百度seo2022新算法更新
  • wap手机网站制作郑州seo排名优化公司
  • 湛江赤坎孵化器网站建设招聘新手小白怎么做跨境电商
  • 做英文网站需要多长时间上海的重大新闻
  • 课程网站建设总体情况企业培训系统app
  • 建湖网站设计推广手段
  • 创建网站用什么语言b2b网站
  • HTML可以做彩票网站吗快速优化关键词排名
  • 买表的网站seo是什么意思啊
  • net网站开发环境青岛百度网站排名优化
  • 安徽六安职业技术学院衡阳seo外包