逐步实现TCP服务端Step02-2:改进

到目前为止服务端处理消息的情况是这样的:

先从socket缓冲中尽力取字节,把取到的字节放到一个单字节数组中去(recv字节队列)。然后,从这个数组中取字节,组成消息。

每次要发送消息时,都要先尝试发送post字节队列中残留的字节,然后再去发送本次实际要发送的字节。如果此次发送没有将期望的字节量全部发出,就把剩余的字节存到post队列中,等待下次调用SendOneMessageEx时再尝试发送。

发送字节的操作是在SendOneMessageEx中进行的,如果SendOneMessageEx不被调用的话,残留的字节就没机会被发送。这个地方不太合理,说白了SendOneMessageEx也应该拆成两个过程 ...


逐步实现TCP服务端Step02-1:基于非阻塞socket的处理逻辑

把socket设置成非阻塞,其目的就是不让程序逻辑在网络I/O处阻塞不前。整个程序都将基于这个“不阻塞”的大前提来进行设计。基于非阻塞socket调用recv和send时不会阻挠逻辑向前进行,那么,其包装函数RecvOneMessage和SendOneMessage也要做到不阻挠才合适。否则,若使用这组包装函数去替换原始函数,程序的行为就有可能会偏离我们的预期。

RecvOneMessage函数内部是循环操作,达到目标有可能要进行多次循环。同时,对于阻塞式socket来说,一次循环中的recv调用又有可能发生阻塞。这么看来基于阻塞式socket的RecvOneMessage函数是有可能阻挠逻辑前进的。

那么,基于非阻塞socket的情况呢 ...


Linux守护进程总结(2) : 实现

将一个普通进程改造成守护进程,需要下面几步:

一、fork子进程,退出父进程 - 为下一步创建新会话做准备
fork出的子进程必定与其父同组,且不是该组的首个进程,所以,子进程一定不是该组的组长进程。经过这一步操作,就去掉了进程的进程组组长身份,如果它是组长的话。

二、调用setsid创建新会话
要想使setsid顺利工作,必须要满足一个条件:调用进程不能是进程组的组长进程。这就是上一步工作的目的。

上面这两步是创建守护进程的核心步骤 ...


mmap文件映射bus error

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>

int main(int argc, char** argv)
{
    int fd;
    int* shm_ptr;
    if (argc != 2) {
        std::clog << "Usage: " 
            << argv[0] << " file" 
            << std::endl;
        return -1;
    }
    if ((fd = open(argv[1], O_RDWR | O_CREAT, 0666)) < 0) {
        std::clog << "open failed, " 
            <<  strerror(errno) << std::endl;
        return -1;
    }
    shm_ptr = (int*)mmap(NULL, sizeof(int), 
            PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == shm_ptr) {
        std::clog << "mmap failed, " 
            << strerror(errno) << std::endl;
        return -1;
    }

    *shm_ptr = 0;

    return 0;
}

执行到第31行时出现“bus error ...


Linux守护进程总结(1) : 基本理论

守护进程(daemon):是一种“潜伏”在后台,存活周期较长的进程。对系统使用者来说它的行为是透明的(它本身不透明,用ps命令可以看到),就像幽灵一样。其父亲通常是上帝(init进程)。

为什么需要守护进程这种形式呢?因为我们有时会开发一些所谓的“服务”程序,这种程序启动后不需要与系统使用者进行交互(调试的时候通常需要)。对于这个服务进程来说,一个客户何时来请求服务,是不得而知的。服务进程能做的事情就是守着,有客户进来,它就服务,没客户就接着等。这个驻守的进程,肯定不可以随随便便地就没了,要没也只能是出于我们的意愿故意将其终止的。然而,普通进程是终端一关闭,它就终止了,这显然不符合要求。

另外,既然该类进程不会与系统使用者进行交互 ...


关于Blog的内容分类

  • Language:讨论编程语言本身的内容。

  • Res&Dev ...