最全的Linux教程,Linux从入门到精通
======================
-
linux从入门到精通(第2版)
-
Linux系统移植
-
Linux驱动开发入门与实战
-
LINUX 系统移植 第2版
-
Linux开源网络全栈详解 从DPDK到OpenFlow
第一份《Linux从入门到精通》466页
====================
内容简介
====
本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。
本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。
需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
- 前言
- select的定位与接口分析
- select的特点
- select的缺点
- 基于select的echo服务器代码实现
- telnet测试
前言
对于服务器来讲,需要一刻不停地监听请求,提供服务
我们不希望服务器主程序卡住
服务器监听的本质是:while 1 { 等待数据的到来->数据到来后读取数据 }
由于recv是阻塞等待,所以我们想尽一切办法来处理这个阻塞问题
- 多线程,把每一个链接交给一个新线程处理,新线程recv阻塞等待对应套接字的时候不会干扰到主线程;这时,阻塞等待+数据读取由线程全权承担
- 我们让内核帮助我们检测指定的套接字的状态。一旦套接字有数据就绪,就会把某个数据结构的状态设置为就绪,主程序检测到就绪,就会读取数据。这时,主程序只要不停地去检测一批套接字的状态就行。这时,等待由内核帮我们承担,主程序只要承担数据读取的任务
select的定位与接口分析
select的定位:只负责等待,是就绪事件通知机制,它等待IO就绪;唯一和read,write,recv,send不同的是,select可以等待多个文件描述符
来看select接口:
int select(
int nfds,
fd_set \*readfds,
fd_set \*writefds,
fd_set \*exceptfds,
struct timeval \*timeout
);
- timeval结构体:秒+微秒
nullptr:永久等待,直到某个fd就绪才返回
3,0:等待3秒,没有就绪就返回
0,0:没有就绪立马返回 - fd_set:比特位的位置代表文件描述符的编号,比特位的内容代表是否关心
作用:所有关心X事件的文件描述符,都应该添加在这个集合里
输入:用户告诉内核,你要帮我检测一下在这个集合中的fd的X事件
输出:内核告诉用户,你关心的fd,有哪些文件描述符已经就绪了不具有保存sock的功能,只具有通知的能力 - fd_set:位图
/\* fd\_set for select and pselect. \*/
typedef struct
{
/\* XPG4.2 requires this member name. Otherwise avoid the name
from the global namespace. \*/
#ifdef \_\_USE\_XOPEN
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define \_\_FDS\_BITS(set) ((set)->fds\_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define \_\_FDS\_BITS(set) ((set)->\_\_fds\_bits)
#endif
} fd_set;
fd_set的作用是:比特位的位置代表哪一个文件描述符,比特位0/1代表文件描述符是否就绪
- 返回
读就绪代表该文件描述符的底层数据已经就绪
写就绪代表文件描述符可以继续写了
异常就绪代表哪个文件描述符异常了
so
轮询检测有没有关心的fd就绪,覆盖式地写入位图,返回。所以select需要我们花一点点第三方变量把fds保存起来,一般是数组
在我们通知了一轮就绪的sock之后,可能还需要select帮助我们进行监测其他的fd,所以要对fd_set重新设置,故要提前保存
其中,监听套接字只关心读事件
获取新的fd之后我们不读它,因为我们不知道这个新的fd里面有没有读写事件就绪,所以要等下一轮循环
select的特点
- select只能等待确定数量的文件描述符,有上限,可监控的fd的数量取决于fd_set的大小
- 需要第三方数组存储fd
- 每次循环都需要更新nfds的值
select的缺点
- 每次调用select, 都需要手动设置fd集合, 从接口使用角度来说也非常不便
- 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
- 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
- select支持的文件描述符数量太小
基于select的echo服务器代码实现
- socket.hpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
namespace ns_sock
{
static const int BACKLOG = 5;
enum {
SOCKET_ERROR = 2,
BIND_ERROR,
LISTEN_ERROR,
ACCEPT_ERROR
};
class Sock {
public:
static int Socket() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1) {
std::cerr << "create socket failed" << std::endl;
exit(SOCKET_ERROR);
}
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
return sock;
}
static void Bind(int sock, uint16\_t port) {
sockaddr_in local;
bzero(&local, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
if(bind(sock, (struct sockaddr\*)&local, sizeof(local)) == -1) {
std::cerr << "bind error" << std::endl;
exit(BIND_ERROR);
}
}
static void Listen(int sock) {
if(listen(sock, BACKLOG) == -1) {
std::cerr << "listen failed" << std::endl;
exit(LISTEN_ERROR);
}
}
static void Accept(){}
};
}//ns\_sock
- select.hpp
#pragma once
#include "sock.hpp"
#include <sys/select.h>
namespace ns_select_server
{
static const uint16\_t g_default_port = 8081;
static const int SELECT_ERROR = 6;
static const int BUFFER_SIZE = 4096;
class SelectServer {
public:
SelectServer(int port = g_default_port):\_listen\_sock(-1), \_port(port) {
_listen_sock = ns_sock::Sock::Socket();
ns_sock::Sock::Bind(_listen_sock, _port);
ns_sock::Sock::Listen(_listen_sock);
// 初始化第三方数组
for(int i = 0; i < FD_SETSIZE; i++) {
_fd_array[i] = -1;
}
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.youkuaiyun.com/forums/4f45ff00ff254613a03fab5e56a57acb)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**