linux io复用命令,Linux网络编程之IO复用——Select

Linux网络编程之IO复用——Select

Linux网络编程之IO复用——Select

IO复用使得程序能够同时监听多个文件描述符,可以大大提高程序的性能。

select 系统调用

select系统调用的用途是:在一段指定的时间内,监听用户感兴趣的文件描述符上的可读、可写和异常事件。

#include

int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,struct timeval* timeout);

/*

* 成功时返回就绪文件描述符总数

* 如果没有任何文件描述符就绪,select返回0

* 失败返回-1

*/

nfds参数指定被监听的文件描述符的总数,一般设置为select监听的所有文件描述符最大值+1,因为文件描述符从0开始。

readfds、writefds、exceptfds参数分别指向可读、可写和异常等事件对应的文件描述符集合。

应用程序调用select时,通过这三个参数传入自己感兴趣的文件描述符,select调用返回时,内核将修改它们来通知应用程序哪些文件描述符 已就绪。

因为内核会对其进行修改,所以就需要进行保存。

这三个参数对应的fd_set其实就是一个整形数组,该数组的每个元素的每一位标记一个文件描述符。

1623b719a0f6d9f12f6a8aff31849d7c.png

-timeout设置select的超时时间。

修改fd_set结构体

#include

FD_ZERO(fd_set* fdset);//清除fdset所有位

FD_SET(int fd, fd_set* fdset);//设置fdset的位fd

FD_CLR(int fd, fd_set* fdset);//清除fdset的位fd

int FD_ISSET(int fd, fd_ste* fdset);//测试fdset的位fd是否被设置

beee55d5f9823bd17c85de66411b3042.png

头文件 tcp_socet.h

#pragma once

#pragma once

#include

#include

#include

#include

#include

#include

#include

#define BUFF_SIZE 128

using namespace std;

class Socket

{

public:

Socket()

{

sockfd_ = socket(PF_INET, SOCK_STREAM, 0);

assert(sockfd_ >= 0);

}

int Get_socket()

{

return sockfd_;

}

~Socket()

{

close(sockfd_);

}

protected:

int sockfd_;

};

class Socket_Ser :public Socket

{

public:

Socket_Ser(const char* ip, int port = 6000, int backlog = 5)

{

struct sockaddr_in address;

memset(&address, 0, sizeof(address));

address.sin_family = AF_INET;

address.sin_port = htons(port);

address.sin_addr.s_addr = inet_addr(ip);

int ret = bind(sockfd_, (struct sockaddr*)&address, sizeof(address));

assert(ret != -1);

ret = listen(sockfd_, backlog);

assert(ret != -1);

}

int Accept()

{

struct sockaddr_in client;

socklen_t len = sizeof(client);

int connfd = accept(sockfd_, (struct sockaddr*)&client, &len);

return connfd;

}

};

class Socket_Cli :public Socket

{

public:

Socket_Cli(const char* ip, int port = 6000)

{

struct sockaddr_in address;

memset(&address, 0, sizeof(address));

address.sin_family = AF_INET;

address.sin_port = htons(port);

address.sin_addr.s_addr = inet_addr(ip);

int ret = connect(sockfd_, (struct sockaddr*)&address, sizeof(address));

assert(ret != -1);

}

void Over_connect()

{

close(sockfd_);

}

};

头文件tcp_select.h

#pragma once

#include "tcp_socket.h"

class Select

{

public:

Select()

{

FD_ZERO(&readfds_);

FD_ZERO(&exceptfds_);

FD_ZERO(&writefds_);

}

void Using_Select(int serfd)

{

int ret = select(serfd + 1, &readfds_, NULL, NULL, NULL);

if (ret < 0)

{

cout << "selcet failure" << endl;

}

}

public:

void Join_Read(int connfd)

{

FD_SET(connfd, &readfds_);

}

void Join_Write(int connfd)

{

FD_SET(connfd, &writefds_);

}

void Join_Except(int connfd)

{

FD_SET(connfd, &exceptfds_);

}

public:

int Judge_Read(int connfd)

{

return FD_ISSET(connfd, &readfds_);

}

int Judge_Write(int connfd)

{

return FD_ISSET(connfd, &writefds_);

}

int Judge_Except(int connfd)

{

return FD_ISSET(connfd, &exceptfds_);

}

public:

void Zero()

{

FD_ZERO(&readfds_);

FD_ZERO(&exceptfds_);

FD_ZERO(&writefds_);

}

private:

fd_set readfds_;

fd_set writefds_;

fd_set exceptfds_;

};

主文件tcp_select.cpp

#include "tcp_select.h"

#include

void Deal_connect(Socket_Ser& ser, Select& sel, list& mylist)

{

int sockfd = ser.Get_socket();

for (auto it = mylist.begin();it!=mylist.end();it++)

{

if (sel.Judge_Read(*it))//当发生读事件

{

if (*it == sockfd)//服务器接受新连接

{

int connfd = ser.Accept();

mylist.push_front(connfd);

cout << "new client:" << connfd << " connet!" << endl;

}

else//客户端发送消息

{

char buffer[BUFF_SIZE];

memset(buffer, '\0', BUFF_SIZE);

int ret = recv(*it, buffer, BUFF_SIZE - 1, 0);

if (strcmp(buffer, "end") == 0) break;

cout << "recv form " << *it << ":" << buffer<< endl;

send(*it, "ok", 2, 0);

}

}

}

}

int Get_max(Select& sel,list& mylist)//得到最大的文件描述符值,并重新设置读事件数组

{

sel.Zero();

auto it = mylist.begin();

int max = *it;

for (; it != mylist.end(); it++)

{

sel.Join_Read(*it);

if (*it > max)

{

max = *it;

}

}

return max;

}

int main(int argc,char* argv[])

{

if (argc <= 1)

{

cout << "error! please input again" << endl;

return 1;

}

list cli_list;//存储连接的套接字

Socket_Ser ser(argv[1]);

Select sel;

cli_list.push_front(ser.Get_socket());

while (1)

{

int maxfd = Get_max(sel,cli_list);

sel.Using_Select(maxfd);

Deal_connect(ser, sel, cli_list);

}

return 0;

}

参考文献

[1]游双.Linux高性能服务器编程.机械工业出版社,2043.5.

Linux网络编程之IO复用——Select相关教程

Linux命令

Linux命令 1、压缩和解压缩 # 压缩 createtar -zcvf 压缩包名 压缩的文件和目录tar -zcvf 1.tar.gz * # 把当前目录下所有文件和目录 打包压缩成1.tar.gz # 解压缩 xtar -zxvf -z # gzip 算法格式-c # 打包-x # 解包-v # 显示详细过程-f # 指定压缩包名字 2、

Linux常用命令一一网络通讯篇

Linux常用命令一一网络通讯篇 Linux常用命令中,要想查看一下网络通讯信息,比如说ifconfig、netstat等,如果你还不会使用,那么最好花几分钟学习一下。 telnet 远端登入 功能:执行telnet指令开启终端机阶段作业,并登入远端主机。 telnet 命令用于远端登入

Linux之重定向

Linux之重定向 1:标准输出 重定向 :把标准输出 重定向到新文件 标准错误不适用 会覆盖已有文件 无屏显,内容都存到httpd 2::追加符,不覆盖原有文件。 1) tee:类似,但只能从管道接收数据 tee -a:类似追加符 tee和tee -a都会屏显,号,追加符不屏显 tee和的

linux centos下安装最新版Vim8.2

linux centos下安装最新版Vim8.2 linux centos下安装最新版Vim8.2 首先卸载低版本Vim yum remove vim 然后下载最新版Vim8.2文件 并上传 vim官网:https://www.vim.org/ Vim8.2下载:https://ftp.nluug.nl/pub/vim/unix/vim-8.2.tar.bz2 下载得到文件:vim-8.2

linux安装rabbitmq-记一次心酸历程

linux安装rabbitmq-记一次心酸历程 环境:linux-centos7.x-64位 JDK1.8 rabbitmq版本:rabbitmq-server-3.8.5-1.el7.noarch 附加:linux宝塔面板 参考: 1.https://www.cnblogs.com/hnusthuyanhua/p/13528217.html 2.https://www.cnblogs.com/shihaiming/p/11

Win7下使用U盘安装linux Ubuntu16.04双系统图文教程

Win7下使用U盘安装linux Ubuntu16.04双系统图文教程 Ubuntu 16.04LTS(长期支持版) 镜像: 下载地址: ( Ubuntu中国下载地址:) 根据自己计算机的配置信息下载(本人下载的是的 64位的) 百度下载 ultraISO软件安装并打开 (傻瓜式安装就可以了) 开始写入

Linux网络通信—Socket(TCP实现)

Linux网络通信—Socket(TCP实现) 一、socket概述 为了简化开发通信程序的工作,由Berkely学校开发了一套网络通信程序的API函数标准。 二、SOCKET分类 流式套接字(SOCK_STREAM) 流式的套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP 保证

Win10 在Microsoft Store安装Kali linux时,报错0x8007019e的解

Win10 在Microsoft Store安装Kali linux时,报错0x8007019e的解决方法 微软商店安装Kali linux 时报错如下: Installing, this may take a few minutes.WslRegisterDistribution failed with error: 0x8007019eThe Windows Subsystem for Linux optional corr

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值