2015-11-24 10:34:09 JektonLuo 阅读数 624
  • Proxmox VE超融合集群生产环境项目实操

    本课程基于真实的生产环境,把整个实施过程都录制下来了,包括到机房去部署系统(可以听到机房服务器的轰鸣声),观看视频,犹如亲临现场。 Proxmox是kvm业界的巅峰之作,去中心化的集群、去中心化的分布式存储,使得只要集群能够维持,可是在任意物理节点发生down机的情况下保持服务的高可用性。免费且开源、简单易用又无功能限制。到目前为止,本人已经部署了若干套proxmox VE超融合集群,无故障运行时间最长的项目,有超过一年的。 鉴于多个平台长期稳定运行取得的经验,又正好遇上新的项目实施,因此特意把整个过程录制下来,希望对大家的实际工作有所帮助,也能少走弯路少采坑。 本项目使用三台物理服务器,目标旨在把两个机柜的业务全部整合到这个proxmox VE超融合集群中,大大降低费用、简化管理和提高可用性。

    86 人正在学习 去看看 田逸

Linux 共有两种信号量——内核信号量和System V IPC 信号量,这里仅讨论内核信号量所用到的子程序 __down()Linux 2.6.11.12) ,其他讨论见《深入理解Linux内核》(Understanding the Linux Kernel, 2nd edition, 中文版211页,英文版208页,顺带对国人翻译书名的功力表示称(tu)赞(cao))。


这里先放一下主要的代码,方便后面讨论

// file: include/asm-i386/semaphore.h
struct semaphore {
    atomic_t count;
    int sleepers;
    wait_queue_head_t wait;
};


// file: arch/i386/kernel/semaphore.c
fastcall void __sched __down(struct semaphore * sem)
{
    struct task_struct *tsk = current;
    DECLARE_WAITQUEUE(wait, tsk);
    unsigned long flags;

    tsk->state = TASK_UNINTERRUPTIBLE;
    spin_lock_irqsave(&sem->wait.lock, flags);
    add_wait_queue_exclusive_locked(&sem->wait, &wait);

    sem->sleepers++;
    for (;;) {
        int sleepers = sem->sleepers;

        /*
         * Add "everybody else" into it. They aren't
         * playing, because we own the spinlock in
         * the wait_queue_head.
         */
        if (!atomic_add_negative(sleepers - 1, &sem->count)) {
            sem->sleepers = 0;
            break;
        }
        sem->sleepers = 1;  /* us - see -1 above */
        spin_unlock_irqrestore(&sem->wait.lock, flags);

        schedule();

        spin_lock_irqsave(&sem->wait.lock, flags);
        tsk->state = TASK_UNINTERRUPTIBLE;
    }
    remove_wait_queue_locked(&sem->wait, &wait);
    wake_up_locked(&sem->wait);
    spin_unlock_irqrestore(&sem->wait.lock, flags);
    tsk->state = TASK_RUNNING;
}


若欲获取信号量时,可调用down()函数,down()原子地(atomic)将sem->count减1并检查它是否小于0。结果大于或等于0,说明资源可用(由于semaphore通常用于保护某一资源,在不引起歧义的情况下,文中之semaphore与“资源”二者可互换,表意相同),down()函数立即返回。否则,表明此时该资源被其他进程所占用,down()即调用__down(),以等待其他进程释放资源。


__down()函数中最令人费解的,莫过于下面这么一小段

if (!atomic_add_negative(sleepers - 1, &sem->count)) {
    sem->sleepers = 0;
    break;
}

注: atomic_add_negative(int i, atomic_t *v)i加到*v,并测试*v是否为负。


即便是结合那少有的注释,也颇为费解。下面分两种情形讨论:

1. 只有一个进程等待信号量

此时,由于down()里的减一操作,现在有count == -1,执行上面的if语句时,sleepers == 1,结果呢,atomic_add_negative(sleepers - 1, &sem->count)并不改变count的大小(即该表达式执行后,count仍为-1),从而表达式返回真,加上前面的!运算符,使得if内代码块(block)并不执行。

随即,进程将sem->sleepers设为1,调用schedule()切换至其他进程(注意,此时进程状态为TASK_UNINTERRUPTIBLE,除非有人从等待队列上唤醒他(通常,由up()唤醒,下面会看到,__down()函数也可能会唤醒等待队列中的进程),不然进程将会一直休眠)。

突然,资源的拥有者释放该信号量(++count),并唤醒等待队列中的进程(这里,队列中仅有一个进程)。随即,该醒来的进程再次执行至上面的if语句,此时,由于count == 1if的条件测试将成立,此时函数返回,刚进程成为资源的拥有者(之一)。


2. 多个进程同时抢夺资源

假设现在有多个进程执行至__down()的临界区(critical section)前,由于每个进程都在down()函数中对sem->count减一,此时,sem->count必然小于-1。

然后,第一个获得锁的进程进入临界区,和情况1一样分析的一样,if的条件测试失败,旋即将sem->sleepers设置为1并调用schedule(),此时,sem->count并未发生变化。

接着,第二个进程进入临界区,执行sem->sleepers++后,sleepers == 2,于是,在if语句的条件测试中,sem->count加1。尽管如此,count仍为负。与第一个进程一样,他将sleepers设置为1后(这一步非常关键),调用schedule()

再往后,第三个进程也开始执行临界区中的代码,和第二个一样,他将count加1后,便继续休眠。

现在,我们应该能够理解源代码中注释那句 Add “everybody else” into it 的含义了。除了第一个(或者说,等待队列中的某一个),其他线程都将count加1,而每个进程都对count执行减1操作,最后,count将等于-1。其结果就像,虽然有多个进程在等待,但在临界区的那一个眼里,就像只有自己在等待资源一样(count == -1, sleepers == 1)。

终于,信号量被释放,count增加1。等待队列也被唤醒。某个幸运儿又一次执行到那个if语句。现在,count == 0,于是,if语句块终于得以重见天日,进程获得资源了!。他将自己移出等待队列,并唤醒其他进程(semaphore初始值可能大于1,多个进程可以同时获得资源)。

假设,semaphore的初值为1(即,一个mutex)。于是便有count == 0, sleepers == 0。此时,另一个进程醒来,继续执行schedule()后的代码,马上的,又遇到了我们的老朋友——那个if语句。测试语句再次被执行后,结果有了count == -1。紧接着,执行sem->sleepers = 1。好了,一切都归于平静,又回到了count == -1, sleepers == 1

故事基本就到这里结束了,虽然有多个进程同时争夺信号量,他们依然可以和谐共处,一切都是那么的美好,优雅。

2019-06-18 14:06:05 u010304442 阅读数 411
  • Proxmox VE超融合集群生产环境项目实操

    本课程基于真实的生产环境,把整个实施过程都录制下来了,包括到机房去部署系统(可以听到机房服务器的轰鸣声),观看视频,犹如亲临现场。 Proxmox是kvm业界的巅峰之作,去中心化的集群、去中心化的分布式存储,使得只要集群能够维持,可是在任意物理节点发生down机的情况下保持服务的高可用性。免费且开源、简单易用又无功能限制。到目前为止,本人已经部署了若干套proxmox VE超融合集群,无故障运行时间最长的项目,有超过一年的。 鉴于多个平台长期稳定运行取得的经验,又正好遇上新的项目实施,因此特意把整个过程录制下来,希望对大家的实际工作有所帮助,也能少走弯路少采坑。 本项目使用三台物理服务器,目标旨在把两个机柜的业务全部整合到这个proxmox VE超融合集群中,大大降低费用、简化管理和提高可用性。

    86 人正在学习 去看看 田逸

做Linux驱动开发经常要使用到内核相关的函数,本篇只要介绍在做驱动开发的过程中用到的内核函数,为以后开发查询提供方便。

本篇覆盖函数如下

copy_from_user与copy_to_user函数
down_interruptible与down函数
writeX与readX宏函数

1. copy_from_user与copy_to_user函数
copy_from_user:从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0,其函数原型如下:

static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
{
	unsigned long res = n;
	kasan_check_write(to, n);

	if (access_ok(VERIFY_READ, from, n)) {
		check_object_size(to, n, false);
		res = __arch_copy_from_user(to, from, n);
	}
	if (unlikely(res))
		memset(to + (n - res), 0, res);
	return res;
}
  • 检查用户空间地址是否正确
    这一步很有必要,试想一下,如果用户做系统调用时,故意传了一个内核地址下来,如果这里不做检查,这里将是一个很大的漏洞,可以轻而易举的对内核搞破坏。

copy_to_user:从内核空间拷贝数据到用户空间,失败返回没有被拷贝的字节数,成功返回0,其函数原型如下:

static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
{
	kasan_check_read(from, n);   // 与copy_from_user一致,先检查内核空间地址的合法性

	if (access_ok(VERIFY_WRITE, to, n)) {
		check_object_size(from, n, true);
		n = __arch_copy_to_user(to, from, n);
	}
	return n;
}

2. down_interruptible与down函数
down_interruptible函数原型如下:

int down_interruptible(struct semaphore *sem)

该函数的功能就是获得信号量,如果得不到信号量就睡眠,此时没有信号打断,那么进入睡眠。但是在睡眠过程中可能被信号打断,打断之后返回-EINTR,主要用来进程间的互斥同步。

一个进程在调用down_interruptible()之后,如果sem<0,那么就进入到可中断的睡眠状态并调度其它进程运行, 但是一旦该进程收到信号,那么就会从down_interruptible函数中返回。并标记错误号为:-EINTR。一个形象的比喻:小强下午放学回家,回家了就要开始吃饭嘛,这时就会有两种情况:情况一:饭做好了,可以开始吃;情况二:当他到厨房去的时候发现妈妈还在做,妈妈就对他说:“你先去睡会,待会做好了你。”小强就答应去睡会,不过又说了一句:“睡的这段时间要是小红来找我玩,你可以叫醒我。”小强就是down_interruptible,想吃饭就是获取信号量,睡觉对应这里的休眠,而小红来找我玩就是中断休眠。

使用可被中断的信号量版本的意思是,万一出现了semaphore的死锁,还有机会用ctrl+c发出软中断,让等待这个内核驱动返回的用户态进程退出,而不是把整个系统都锁住了。

down函数原型如下:

void down(struct semaphore * sem)

down操作,跟down_interruptible类似,先去获取信号量,如果信号量被占用,先把该进程加入到等待队列。然后查询当前进程是否有信号(软中断)要去处理,如果有的话会返回–EINTR退出;如果没有的话,当前进程进入不可被信号(软中断)唤醒的睡眠,也就是睡眠过程中不响应信号(软中断),直到获取到信号量(flag)退出睡眠,即被 up操作 从等待队列上唤醒。

扩展其他类似函数:

//睡眠的进程能够由于受到致命信号而被唤醒,中断获取信号量的操作
int down_killable(struct semaphore *sem);

//试图获取信号量,若无法获得则直接返回1而不睡眠;返回0则 表示获取到了信号量
int down_trylock(struct semaphore *sem);

//表示睡眠时间是有限制的。假设在jiffies指明的时间到期时仍然无法获得信号量,则将返回错误码
int down_timeout(struct semaphore *sem,long jiffies)

//释放内核信号量锁
void up(struct semaphore *sem)

3. writeX与readX宏函数
writeb(), writew(), writel() 宏函数,其功能往内存映射的 I/O 空间上写数据:

  • writeb() I/O 上写入 8 位数据 (1字节)
  • writew() I/O 上写入 16 位数据 (2字节)
  • wirtel() I/O 上写入 32 位数据 (4字节)
    函数原型如下:
#include <asm/io.h> 

void writeb (unsigned char data , unsigned short addr )
void writew (unsigned char data , unsigned short addr )
void writel (unsigned char data , unsigned short addr )

readb(), readw(), readl() 宏函数,其功能从内存映射的 I/O 空间读取数据:

  • readb 从 I/O 读取 8 位数据 ( 1 字节 )
  • readw 从 I/O 读取 16 位数据 ( 2 字节 )
  • readl 从 I/O 读取 32 位数据 ( 4 字节 )

函数原型如下:

unsigned char readb (unsigned int addr )
unsigned char readw (unsigned int addr )
unsigned char readl (unsigned int addr )
2019-01-23 15:45:54 guangyacyb 阅读数 41
  • Proxmox VE超融合集群生产环境项目实操

    本课程基于真实的生产环境,把整个实施过程都录制下来了,包括到机房去部署系统(可以听到机房服务器的轰鸣声),观看视频,犹如亲临现场。 Proxmox是kvm业界的巅峰之作,去中心化的集群、去中心化的分布式存储,使得只要集群能够维持,可是在任意物理节点发生down机的情况下保持服务的高可用性。免费且开源、简单易用又无功能限制。到目前为止,本人已经部署了若干套proxmox VE超融合集群,无故障运行时间最长的项目,有超过一年的。 鉴于多个平台长期稳定运行取得的经验,又正好遇上新的项目实施,因此特意把整个过程录制下来,希望对大家的实际工作有所帮助,也能少走弯路少采坑。 本项目使用三台物理服务器,目标旨在把两个机柜的业务全部整合到这个proxmox VE超融合集群中,大大降低费用、简化管理和提高可用性。

    86 人正在学习 去看看 田逸

在Linux下想查看shutdown 函数的使用方法,于是执行:

$ man shutdown

但出来的是shutdown 的使用方法:

shutdown(8)                                                        shutdown(8)

NAME
       shutdown - bring the system down

SYNOPSIS
       shutdown [OPTION]...  TIME [MESSAGE]
……

问题来了,man 如何区分Linux命令和C 函数,参考:

How can I get in linux the man page for C functions and not the man with bash commands

于是执行:

$ man 2 shutdown

输出:

SHUTDOWN(2)                Linux Programmer's Manual               SHUTDOWN(2)

NAME
       shutdown - shut down part of a full-duplex connection

SYNOPSIS
       #include <sys/socket.h>

       int shutdown(int sockfd, int how);
……

留意上面有一个SHUTDOWN(2),这个2 是man的分卷号,用 man man 命令查看:

……
MANUAL SECTIONS
       The standard sections of the manual include:

       1      User Commands

       2      System Calls

       3      C Library Functions

       4      Devices and Special Files

       5      File Formats and Conventions

       6      Games et. Al.

       7      Miscellanea

       8      System Administration tools and Deamons
……

分卷2 是系统调用,分卷3是C库函数,分卷8 是系统管理工具,所以如果直接执行 man shutdown,看到的是系统命令 shutdown,用 man 2 shutdown ,看到的是系统调用shutdown,而 man 3 shutdown 是找不到的,所以如果要用man 查看命令或者系统调用的定义,要在man 后面加上对应的卷标。

 

参考:

How can I get in linux the man page for C functions and not the man with bash commands

linux下使用man查看C函数用法

 

2013-07-16 09:29:15 trochiluses 阅读数 5510
  • Proxmox VE超融合集群生产环境项目实操

    本课程基于真实的生产环境,把整个实施过程都录制下来了,包括到机房去部署系统(可以听到机房服务器的轰鸣声),观看视频,犹如亲临现场。 Proxmox是kvm业界的巅峰之作,去中心化的集群、去中心化的分布式存储,使得只要集群能够维持,可是在任意物理节点发生down机的情况下保持服务的高可用性。免费且开源、简单易用又无功能限制。到目前为止,本人已经部署了若干套proxmox VE超融合集群,无故障运行时间最长的项目,有超过一年的。 鉴于多个平台长期稳定运行取得的经验,又正好遇上新的项目实施,因此特意把整个过程录制下来,希望对大家的实际工作有所帮助,也能少走弯路少采坑。 本项目使用三台物理服务器,目标旨在把两个机柜的业务全部整合到这个proxmox VE超融合集群中,大大降低费用、简化管理和提高可用性。

    86 人正在学习 去看看 田逸
信号量(semaphore)是用于保护临界区的一种常用方法。只有得到信号量的进程才能执行临界区代码,而没有得到信号量的进程进入休眠等待状态。

Linux系统中与信号量相关的操作主要有如下4种。


定义信号量


下面代码定义名为sem的信号量。

struct semaphore sem;

struct semaohore结构体在内核中定义如下:

/include/linux/semaphore.h目录下:

struct semaphore{

       spinlock_t              lock;

       unsigned int           count;

       struct list_head       wait_list;

};


2初始化信号量


/include/linux/semaphore.h目录下,void sema_init(struct semaphore*

sem, int val) 函数用于初始化信号量,并设置信号量sem的值为val。尽管信号量可以被初始化为大于1的值从而成为一个计数信号量,但是它通常不被这样使用。

内核定义了两个宏来把sem的值设置为1或者0

#define init_MUTEX(sem)                  sema_init(sem, 1)

#define init_MUTEX_LOCKED(sem)         sema_init(sem, 0)

使用init_MUTEX(sem) 初始化信号量时,表示信号量最初是可以被获取的。而使用init_MUTEX_LOCKED(sem) 初始化信号量时,此信号量只有先被释放才可以获取。


3获取信号量


void down(struct semaphore *sem);

该函数用于获取信号量sem,它会导致睡眠,因此不能在中断上下文使用。

在内核里该函数的源代码如下:

kernel/semaphore.c文件里:

53 void down(struct semaphore *sem)

 54 {

 55         unsigned long flags;

 56

 57         spin_lock_irqsave(&sem->lock, flags);

 58         if (likely(sem->count > 0))

 59                 sem->count--;

 60         else

 61                 __down(sem);

 62         spin_unlock_irqrestore(&sem->lock, flags);

 63 }

这里重点看58行:if (likely(sem->count > 0)),这句话表示当获取信号量成功时,就执行sem->count—; 即对信号量的值减一。else表示获取信号量失败,此时调用__down函数进入睡眠状态,并将此进程插入到等待队列尾部。

内核定义了信号量的等待队列结构体:

193 struct semaphore_waiter {

194         struct list_head list;

195         struct task_struct *task;

196         int up;

197 };

此结构体是一个双向循环链表。

int down_interruptible(struct semaphore *sem);

该函数功能与down()类似,不同之处是,down()在获取信号量失败进入睡眠状态时的进程是不能被打断的,而down_interruptible()在进入睡眠状态时的进程能被信号打断,信号也会导致函数返回。下面我们也来看一看这个函数的源码:

kernel/semaphore.c文件里:

75 int down_interruptible(struct semaphore *sem)

 76 {

 77         unsigned long flags;

 78         int result = 0;

 79

 80         spin_lock_irqsave(&sem->lock, flags);

 81         if (likely(sem->count > 0))

 82                 sem->count--;

 83         else

 84                 result = __down_interruptible(sem);

 85         spin_unlock_irqrestore(&sem->lock, flags);

 86

 87         return result;

 88 }

这里我们可以看到,当获取信号量成功时,返回0,而获取信号量失败时,返回一个非0的值。在使用down_interruptible()函数获取信号量时,对返回值一般会进行检查,如果非0,通常立即返回-ERESTARTSYS。如:

if ( down_interruptible(&sem) )

                     return -ERESTARTSYS;

这里还有一个问题:在获取信号量失败后,为什么down不能被中断,而down_interruptible却可以被中断呢?我们从downdown_interruptible的源代码可以得知,在获取信号量失败后,down函数运行了__down函数,而down_interruptible函数运行了__down_interruptible。那么让我们来看一下这两个函数的源码:

kernel/semaphore.c文件里:

236 static noinline void __sched __down(struct semaphore *sem)

237 {

238   __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);

239 }

240

241 static noinline int __sched __down_interruptible(struct semaphore *sem)

242 {

243 return __down_common(sem,TASK_INTERRUPTIBLE,                     MAX_SCHEDULE_TIMEOUT);

244 }

__down函数里,是把进程的状态设置为TASK_UNINTERRUPTIBLE ,即不可中断状态。

而在__down_interruptible里,是把进程的状态设置为TASK_INTERRUPTIBLE ,即可中断状态。这就解释了以上提出的问题。

4释放信号量

void up(struct semaphore *sem);

该函数用于释放信号量sem,唤醒等待者。

它的源代码如下:

178 void up(struct semaphore *sem)

179 {

180         unsigned long flags;

181

182         spin_lock_irqsave(&sem->lock, flags);

183         if (likely(list_empty(&sem->wait_list)))

184                 sem->count++;

185         else

186                 __up(sem);

187         spin_unlock_irqrestore(&sem->lock, flags);

183行的语句中,up函数首先判断等待队列是否为空,如果是空的话,就执行sem->count++;否则,执行__up() 函数,释放掉等待队列尾部的信号量。

信号量用于同步举例:

 

 

   


如果信号量被初始化为0,则它可以用于同步,同步意味着一个执行单元的继续执行需要等待另一个执行单元完成某事,保证执行的先后顺序。

如上图所示,执行单元A执行代码区域a之前,必须等待执行单元B执行完代码区域b后释放信号量给它。

以下模块很好地使用了信号量:

#include <linux/init.h>

#include <linux/module.h>

#include <linux/sched.h>

#include <linux/sem.h>

 

struct semaphore sem1;

struct semaphore sem2;

 

int num[2][5] = {

       {0,2,4,6,8},

       {1,3,5,7,9}

};

int thread_one(void *p);

int thread_two(void *p);

int thread_one(void *p)

{

       int *num = (int *)p;

       int i;

       for(i = 0; i < 5; i++){

              down(&sem1);      //获取信号量1

              printk("%d ", num[i]);

              up(&sem2);    //释放信号量2

       }

       return 0;

}

int thread_two(void *p)

{

       int *num = (int *)p;

       int i;

       for(i = 0; i < 5; i++){

              down(&sem2);             //获取信号量2

              printk("%d ", num[i]);

              up(&sem1);           //释放信号量1

       }

       return 0;

}

static int lan_init(void)

{

       printk("lan is coming\n");

       init_MUTEX(&sem1);  //初始化信号量1 使信号量1最初可被获取

       init_MUTEX_LOCKED(&sem2);  //初始化信号量2,使信号量2只有被释放后才可被获取

       kernel_thread(thread_one, num[0], CLONE_KERNEL);

       kernel_thread(thread_two, num[1], CLONE_KERNEL);

       return 0;

}

static void lan_exit(void)

{

       printk("\nlan exit\n");

}

module_init(lan_init);

module_exit(lan_exit);


本文来源:谁不小心的CSDN博客 临界资源 互斥访问 内核中的up和down函数

2014-09-01 20:36:14 yusiguyuan 阅读数 3350
  • Proxmox VE超融合集群生产环境项目实操

    本课程基于真实的生产环境,把整个实施过程都录制下来了,包括到机房去部署系统(可以听到机房服务器的轰鸣声),观看视频,犹如亲临现场。 Proxmox是kvm业界的巅峰之作,去中心化的集群、去中心化的分布式存储,使得只要集群能够维持,可是在任意物理节点发生down机的情况下保持服务的高可用性。免费且开源、简单易用又无功能限制。到目前为止,本人已经部署了若干套proxmox VE超融合集群,无故障运行时间最长的项目,有超过一年的。 鉴于多个平台长期稳定运行取得的经验,又正好遇上新的项目实施,因此特意把整个过程录制下来,希望对大家的实际工作有所帮助,也能少走弯路少采坑。 本项目使用三台物理服务器,目标旨在把两个机柜的业务全部整合到这个proxmox VE超融合集群中,大大降低费用、简化管理和提高可用性。

    86 人正在学习 去看看 田逸

在Linux C网络编程中,一共有两种方法来关闭一个已经连接好的网络通信,它们就是close函数和shutdown函数,它们的函数原型分别为:

1 #include<unistd.h>
2 int close(intsockfd)
3 //返回:0——成功, 1——失败
4  
5 #include<sys/socket.h>
6 int shutdown(intsockfd,inthowto)
7 //返回:0——成功, 1——失败

对一个tcp socket调用close()的默认动作是将该socket标记为已关闭并立即返回到调用该api进程中。此时,从应用层来看,该socket fd不能再被进程使用,即不能再作为read或write的参数。而从传输层来看,TCP会尝试将目前send buffer中积压的数据发到链路上,然后才会发起TCP的4次挥手以彻底关闭TCP连接。
       调用close()是关闭TCP连接的正常方式,但这种方式存在两个限制,而这正是引入shutdown()的原因:
       1)close()其实只是将socket fd的引用计数减1,只有当该socket fd的引用计数减至0时,TCP传输层才会发起4次握手从而真正关闭连接。而shutdown则可以直接发起关闭连接所需的4次握手,而不用受到引用计数的限制;
       2)close()会终止TCP的双工链路。由于TCP连接的全双工特性,可能会存在这样的应用场景:local peer不会再向remote peer发送数据,而remote peer可能还有数据需要发送过来,在这种情况下,如果local peer想要通知remote peer自己不会再发送数据但还会继续收数据这个事实,用close()是不行的,而shutdown()可以完成这个任务。


close函数和shutdown函数的第一个参数都是代表的是一个文件描述符。我们知道,在Linux操作系统中,一切东西都是当作文件来对待,所有的东西,诸如设备、内存都模拟成文件;当然,网络之间的通信也不例外。每一个通信对话都有一个文件描述符对应着,你对它们之间的操作就像在操作本地的文件一样。在shutdown函数当中,还有一个参数howto,它有一下三种值

  1. SHUT_RD:关闭读这一半,此时用户不能再从这个套接字读数据,这个套接口接收到的数据都会被丢弃,对等方不知道这个过程。关闭连接的读端。也就是该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被丢弃。进程将不能对该套接字发出任何读操作。对TCP套接字该调用之后接受到的任何数据将被确认然后无声的丢弃掉。
  2. SHUT_WR:相应地关闭写这一半,此时用户不能再向套接字中写数据,内核会把缓存中的数据发送出去,接着不会再发送数据,对等端将会知道这一点。当对等端试图去读的时候,可能会发生错误。
  3. SHUT_RDWR:关闭读与写两半,此时用户不能从套接字中读或写。它相当于再次调用shutdown函数,并且一次指定SHUT_RD,一次指定SHUT_WR。

SHUT_**在函数库里面都是由宏定义的;由于shutdown提供了第二个,它可以精确的控制一个套接字描述符的关闭,这对close函数来说是无法实现的。在多线程环境中,一个描述符可能是被好几个线程复制了,它们与一个文件关联,并且内核维护一个文件引用计数,只有在引用计数为零的情况下close才可以关闭掉这个文件描述符。
使用close函数有两个限制,却可以使用shutdown来避免:

  1. close函数把描述符的引用计数减一,仅仅在该计数变为0的时候,才真正的关闭套接字,而使用shutdown函数可以不管引用计数就激发了TCP的正常连接终止序列;
  2. close函数终止读和写两个方向的数据传输。既然TCP连接是全双工的,有时候我们需要告知对端我们已经完成了数据发送,我们仅仅需要关闭数据发送的一个通道,但是我们还是可以接收到对端发送过来的数据,这种控制只有利用shutdown函数才能实现。
  3. 1>.如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
  4.    2>. 在多进程中如果一个进程中shutdown(sfd,SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程.

linux down up认识

阅读数 834

打印函数地址

阅读数 2122

down_interruptible()

阅读数 1736

没有更多推荐了,返回首页