unix/linux c函数接口大全

作者: 一字马胡
转载标志 【2018-03-27】

更新日志

日期 更新内容 备注
2018-03-27 回顾以前的知识 link from csdn

/这个函数可以将errno直接转换为可读的错误形式/
(1)、char* strerror(int errnum)
/这个函数将直接打印出errno当前值所对应的错误信息打印出来,参数可以指定一个字符串,函数将这个字符串显示在错误信息前面/
(2)、void perror(const char* msg)
/这个函数可以用来获取主机名/
(3)、int gethostname(char* name,size_t size)
/这个函数可以设置主机名/
(4)、int sethostname(const char* name,size_t length)
/这个函数将返回操作系统和主机的信息,保存在参数info里面,那是一个结构体/
(5)、int uname(struct utsname *info)

//-|structure define|-
struct utsname{
    char    sysname[];//os
    char    nodename[];//host name
    char    release[];//os version
    char    release[];//os version level
    char    machine[];//hardware type
};

/这个函数用于获取系统当前系统变量之值,参数为需要查看的系统变量/
(6)、long int sysconf(int parameter)
/这个函数用来获取文件系统限制和选项/
(7)、long int pathconf(const char* pathname,int parameter)
/这个函数一样用来获取文件系统的限制和选项,只是需要提供的是文件描数字/
(8)、long int fpathconf(int filedes,int parameter)
/这个函数可以获得当前工作目录/
(9)、int getcwd(char* buffer,size_t size)
/这个函数用来打开一个文件流/
(10)、FILE* fopen(const char* pathname,const char* opentype)
/这个函数用来关闭一个文件流/
(11)、int fclose(FILE* stream)
/这个函数用来重新打开文件流/
(12)、FILE* freopen(const char* pathname,const charopentype,FILE stream)
/这个函数用来读取一个字符,并且强制转换为int/
(13)、int fgetc(FILE* stream)
/这个函数和fgetc一样,只是可以作为宏使用,而fgetc不可以/
(14)、int getc(FILE* stream)
/这个函数相当于getc(stdin),也就是从标准输入读入/
(15)、int getchar(void)
/这个函数将int c强制转换为unsigned char c,然后写入stream/
(16)、int fputc(int c,FILE* stream)
/可以用宏来实现,其他和fputc一样/
(17)、int putc(int c,FILE* stream)
/标准输出,相当于putc(stdout)/
(18)、int putchar(int c)
/这个函数将连续读取count-1个字符,然后在末尾添加‘\0’,注意如果需要读的字符多了,那么就要多次调用/
(19)、char* fgets(chars,int count,FILE stream)
/这个函数只从标准输入读取,功能和fgets一样,只是一次读完/
(20)、char* gets(char* s)
/这个函数用来从流中读入一行/
(21)、ssize_t getline(char** lineptr,size_t n,FILE* stream)
/这个函数可以自己指定一次读入的终止符,如果指定为'\n',那么就和getline一样/
(22)、ssize_t getdelim(char** lineptr,int size_t n,int delimiter,FILE* stream)
/每次输出一行/
(23)、int fputs(const char* s,FILE* stream)
/每次输出一行到标准输出/
(24)、int puts(const char* s)
/该函数将一个字符回退到读流中,所以下次读的时候从这个字符开始,我们可以想象成是getc的逆操作/
(25)、int ugetc(int c,FILE* stream)
/这个函数将从流中读取指定个数的字符放在相应的位置,count为数据项数,每项大小为size,所以总大小为size×count/
(26)、size_t fread(void* data,size_t size,size_t count,FILE* stream)
/这个函数则可以写到指定的流中count和size大小的数据/
(27)、size_t fwrite(const void* data,size_t size,size_t count,FILE* stream)
/这个函数返回文件当前的位置,是从开始位置起的字节数,失败返回-1/
(28)、long int ftell(FILE* stream)
/这个函数用于改变流的文件位置,whence+offset/
(29)、int fseek(FILE* stream,long int offset,int whence)
/这个函数就是定位到文件的开始/
(30)、void rewind(FILE* stream)
/这个函数将获取文件的当前位置,保存在pos里面/
(31)、int fgetpos(FILE* stream,fpos_t* pos)
/这个函数用来设置流的位置/
(32)、int fsetpos(FILE* stream,fpos_t* pos)
/这个函数将返回0,如果stream的错误指示器被设置/
(33)、int ferror(FILE* stream)
/这个函数返回0,当且仅当文件末尾指示器被设置/
(34)、int feof(FILE* stream)
/这个函数用来清除错误指示器和文件末尾指示器/
(35)、void clearerr(FILE* stream)
/这个函数将打开一个文件描数字(也许创建)/
(36)、int open(const char* filename,int flag [,mode_t mode])
/这个函数用来创建一个新的文件,等价于open(filename,O_WRONLY|O_CREAT|O_TRUNC,mode)/
(37)、int creat(const char* filename,mode_t mode)
/这个函数将关闭一个文件描数字/
(38)、int close(int filedes)
/从文件描数字读/
(39)、ssize_t read(int filedes,void* buf,size_t nbytes)
/向文件描数字写/
(40)、ssize_t write(int filedes,const void* buf,size_t nbytes)
/这个函数用来改变文件描数字的位置/
(41)、off_t lseek(int filedes,off_t offset,int whence)
/这个函数将复制描数字old到新的描数字/
(42)、int dup(int old)
/这个函数将old复制到new/
(43)、int dup2(int old,int new)
/这个函数将使得一个文件描数字与一个流相连,函数返回这个文件描数字关联的流/
(44)、FILE* fdopen(int filedes,const char* opentype)
/这个函数将返回与一个文件流相连的文件描数字/
(45)、int fileno(FILE* stream)
/这个函数可以实现对文件的各自操作,由参数cmd决定是什么操作/
(46)、int fcntl(int filedes,int cmd,...)
/这个函数可以实现散布读,将文件内容读入到内存分散的缓冲区中,iovec是一个结构体,它拥有数据区的开始地址和大小/
(47)、ssize_t readv(int filedes,const struct iovec* iov,int iovcnt)
/这个函数实现聚集写,收集内存中分散的缓冲区中的数据写至文件的连续区间,iovec是一个结构体,他拥有数据区的开始地址和大小/
(48)、ssize_t writev(int filedes,const struct iovec* iov,int iovcnt)
/这个函数可以用来查看指定文件的特征,返回链接所引用的文件的特征/
(49)、int stat(const char* pathname,struct stat* buf)
/这个文件用来查看指定文件的特诊,返回链接本身的文件特征/
(50)、int lstat(const char* pathname,struct stat* buf)
/这个文件返回与文件描数字相连的文件特征/
(51)、int fstat(int filedes,struct stat* buf)
/这个函数实现链接文件,就是多个文件名表示同一个文件,注意,只有一个inode,这是属于硬链接的/
(52)、int link(const char* existingpath,const char* newpath)
/这个函数实现符号链接,不直接指向inode,而是指向文件的路径名,这个文件可以不存在/
(53)、int symlink(const char* path,const char* sympath)
/这个函数则打开参数给定的符号链接文件,读出内容放在相应的地方,然后关闭文件/
(54)、int readlink(const char* pathname,char* buf,int bufsize)
/这个函数将改变文件的属主id和组id,改变的是实际文件/
(55)、int chown(const char* pathname,uid_t owner,gid_t group)
/这个函数改变文件的属主id和组id/
(56)、int fchown(int filedes,uid_t owner,gid_t group)
/这个函数用来改变文件的属主id和组id,改变符号链接文件/
(57)、int lchown(const char* pathname,uid_t owner,gid_t group)
/这个函数将设置进程的当前文件创建屏蔽,返回老的,不影响父进程/
(58)、mode_t umask(mode_t cmask)
/这个函数用来改变文件的访问方式,如果是符号链接,则改变的是指向的文件而不是本身/
(59)、int chmod(const char* filename,mode_t mode)
/这个函数将改变文件的访问方式,如果是符号链接,改变的是文件本身/
(60)、int fchmod(int filedes,mode_t mode)
/这个函数用来测试一个用户是否有权操作一个文件/
(61)、int access(const char* filename,int how)
/这个函数用来截断文件,使得一个已经存在的文件大小变为指定长度的大小/
(62)、int ftruncate(int filedes,off_t length)
/这个函数用来截断文件,使得一个已经存在的文件大小变为指定长度的大小/
(63)、int truncate(const char* pathname,off_t length)
/这个函数用来改变文件的访问时间和修改时间/
(64)、int utime(const char* pathname,const struct utimebuf* times)
/这个函数页用来改变文件的访问时间和修改时间,数组第一个用来改变文件的访问时间,第二个参数就是修改时间/
(65)、int utimes(const char* path,const struct timeval values[2])
/这个函数将删除一个文件名,并减少此文件的链接次数,如果计数为0,那么文件内容被删除/
(66)、int unlink(const char* pathname)
/这个函数将删除一个目录/
(67)、int rmdir(const char* pathname)
/这个函数既可以用来删除文件,也可以用来删除目录/
(68)、int remove(const char* pathname)
/这个函数用来修改文件名和目录名/
(69)、int rename(const char* oldname,const char* newname)
/这个函数将得到进程的当前工作目录/
(70)、char* getwd(char* pathbuf)
/这个函数比较厉害,可以改变进程的工作目录到指定的目录,对父进程没有影响/
(71)、int chdir(const char* pathname)
/这个函数则实现和chdir一样,只是参数不一样/
(72)、int fchdir(int filedes)
/这个函数将创建一个目录/
(73)、int mkdir(const char* pathname,mode_t mode)
/目录也是一种文件,所以可以读目录流,该函数是第一步,即打开目录,返回指向其DIR的指针/
(74)、DIR* opendir(const char* dirname)
/这个函数读取目录DIR中的一个目录,而且使得指向下一项/
(75)、struct dirent* readdir(DIR* dirp)
/函数关闭一个目录流/
(76)、closedir(DIR* dirp)
/该函数将恢复dirp所指向的目录流指向第一项目录/
(77)、void rewinddir(DIR* dirp)
/该函数返回目录当前位置/
(78)、long int telldir(DIR* dirp)
/设置目录位置,参数loc应该是telldir返回的结果/
(79)、void seekdir(DIR* dirp,long int loc)
/这是环境表指针,其中的内容形如name=value/
(80)、extern char** environ;
/这个函数将返回指定名字的环境的值/
(81)、char* getenv(const char* name)
/该函数可以用来设置一个环境变量或者去掉一个环境变量/
(82)、int putenv(char* str)//the str just like=>name=value
/这个函数将终止进程/
(83)、void exit(int status)
/这个函数将流产进程,因为该函数将生成一个转储文件/
(84)、void abort()
/这个函数将实现动态分配内存/
(85)、void* malloc(sise_t size)
/这个函数和malloc一样,只是常用来为结构体分配内存/
(86)、void* calloc(size_t num_of_elem,size_t ele_size)
/这个函数用来重新分配村内,需要十分小心的使用/
(87)、void* realloc(void* ptr,size_t newsize)
/这个函数释放动态分配的内存/
(88)、void free(void* ptr)
/这个函数将获得进程的资源限制,resource 参数指明那种资源/
(89)、int getrlimit(int resource,struct rlimit* rlptr)
/这个函数用来设置进程资源限制,resources指明要设置哪种资源/
(90)、int setrlimit(int resource,const struct rlimit* rlptr)
//-|structure define|-
struct rlimit{
rlim_t rlim_cur;//current limit
rlim_t rli_max;//max (machine) lmit
};
/这个函数用来获取进程的资源使用情况,比如用了多少cpu,缺页次数等等/
(91)、int getusage(int who,struct rusage* rusage)

//-|structure define|-
struct rusage{
    struct timeval ru_utime;//run user instructions
    struct timeval ru_stime;//run os with process
}
//-|structure define|-
struct timeval{
       time_t   tv_Sec;
       suseconds  tv_usec;
}

/这个函数将返回用户名/
(92)、char* getlogin()
/这个函数将返回进程的实际用户id/
(93)、uid_t getuid()
/这个函数将返回进程的有效用户id/
(94)、uid_t geteuid()
/函数将返回进程的实际组id/
(95)、gid_t getgid()
/函数返回进程的有效组id/
(96)、gid_t getegid()
/获取进程id和父进程id/
(97)、pid_t getpid()|getppid()
/创建进程/
(98)、pid_t fork()//返回0表示是子进程,其他表示父进程

/这个函数将等待进程完成/
(99)、pid_t wait(int stat_loc)|pid_t waitpid(pid_t pid,int stat_loc,int options)
/这个函数将执行一个新程序/
(100)、int system(const char* command)
/这个函数将信号数signo对于的描述信息,如果msg不是空指针的话,那么函数将用这个msg作为前缀输出/
(101)、void psignal(int signo,char* msg)
/这个函数将简单的发送一个信号给调用他的进程/
(102)、int raise(int signo)
/这个函数将发送一个信号给一个进程或者一个进程组,sig指明要发送的信号/
(103)、int kill(pid_t pid,int sig)
/我们当然可以设置信号的动作,所以下面这个函数用来设置信号发生时的动作,[void(sighandler_t)(int)]/
(104)、sighandler_t signal(int signum,sighandler_t handler)
/
还有一个函数可以设置信号动作,这个函数将更加安全/
(105)、int sigaction(int signum,const struct sigaction
act,struct sigaction* oact)

//-|structure define|-
struct sigaction{
    void   (*sa_handler)();
    void   (*sa_sigaction)(int,siginfo_t*,void*);
    sigset_t    sa_mask;
    int         sa_flags;
};

//--set-- 下面这些函数完成信号集操作
(106)、int sigemptyset(sigset_t* set) //将set清空
(107)、int sigfillset(sigset_t* set)//使得set包含所有信号,和sigemptyset是相反的
(108)、int sigaddset(sigset_t* set,int signo) //将信号signo加到set集合里面去
(109)、int sigdelset(sigset_t* set,int signo) //将信号signo从set里面移除
(110)、int sigismember(const sigset_tset,int signo) //查看signo信号是不是在信号集合set里面
/
该函数将设置进程想要阻塞的信号/
(111)、int sigprocmask(int how,const sigset_t
set,sigset_t* oset)
/已经发生但是还未交付的信号称为悬挂信号,我们可以用这个函数来检测是否有悬挂信号,参数就是返回的悬挂信号集合/
(112)、int sigpending(sigset_t* set)
/这个函数用来等待信号,简单的悬挂进程知道信号到达/
(113)、int pause()
/这个函数将更加高级,可以指定那些我们不关心的信号,所以只有当出现不包含在参数信号集合里面的信号时,才会唤醒进程/
(114)、int sigsuspend(const sigset_t* sigmask)
/这个函数将返回unix纪元(总秒数),如果loc是非空指针,那么loc里面也将会有一个副本/
(115)、time_t time(time_t* loc)
/这个函数将计算两个时间之间的差,结果作为双精度浮点返回/
(116)、double difftime(time_t time1,time_t time2)
//--set-- 下面的函数将是以微妙为单位的
(117)、int gettimeofday(struct timeval* restrict tp,void* restrict tzp)//将返回描述和微妙数在第一个参数里面,我们不需要知道第二个参数(时区)
(118)、int settimeofdat(const struct timeval* tp,const void* tzp) //这个函数将设置当前时间为tp,当然只有特权用户才有这样的资格
(119)、int adjtime(const struct timeval* delta,struct timeval* olddelta) //对时钟做微调,如果为负数,则系统将走慢一点直到过去那么多时间
//--set-- 下面这组函数是对上面函数的操作,也就是将描述或者微妙数转换为tm结构
(120)、struct tm* gmtime(const time_t* time) //你需要提供一个time_t类型的指针,函数将这个指针所指向的时间转换为tm
(121)、struct tm* localtime(const time_t* time) //这个函数将time转换为本地时间,很复杂,但是使用很简单
(122)、time_t mktime(struct tm* brokentime) //这个函数将tm结构的时间转换为time_t类型
//--set-- unix提供了可以将tm或者time_t时间转换为可读的形式的函数
(123)、char* asctime(const struct tm* timeptr) //将timptr转化为可读的形式返回
(124)、char* ctime(const time_t* timeval) //将timeval转换为可读的形式返回
//--comment-- cpu时间和墙钟时间,cpu时间也就是进程实际占用cpu运行的时间,而墙钟时间则是从进程开始便开始计时的
//--comment-- 所以墙钟时间可能包含有其他进程运行的时间,当然,cpu时间又分为用户时间和系统时间,用户时间就是cpu执行
//--comment-- 用户指令的时间,而系统时间就是系统为执行进程而运行的一些时间,比如系统调用时间

/这个函数将返回进程当前的cpu时间,包括用户时间和系统时间/
(125)、clocl_t clock() //clock_t 表示系统内部使用的时间单位,为了将返回时间变为秒,需要除以CLOCK_PER_SEC
/这个函数报告更加详细的cpu时间,包括自己用去的时间,系统为自己服务用去的时间,子进程的时间,同时还返回系统当前的墙钟时间/
(126)、clock_t times(struct tms* buff)

//-|structure define|-
struct tms{
     clock_t   tms_utime;//user cpu time
     clock_t   tms_stime;//system cpu time
     clock_t   tms_cutime;//child user cpu time
     clock_t   tms_cstime;//child system cpu time
}

/这个函数将使得进程睡眠一段时间,它挂起调用进程直到发生下面的事情:(1)、时间到(2)、信号到/
(127)、unsigned int sleep(unsigned int seconds) //注意,参数单位是秒,不是微妙
/这个函数用来设置一次性的定时,只能设置墙钟时间,到期会生成SIGALRM信号,如果进程没有捕捉该信号,默认会结束该进程/
(128)、unsigned int alarm(unsigned int seconds)
//--set-- 下面的函数可以用来设置或者获取三种定时器
(129)、int setitimer(int which/whick clock/,const struct itimevalvalue,struct itimerval ovalue)
(130)、int getitimer(int which,struct itimerval* value)

//-|structure define|-
struct itimerval{
     struct timeval  it_interval;//定时器的间隔时间
     struct timeval  it_value;//定时器的开始时间
}

//--comment-- 关于实时时钟,系统定义的实时时钟有几种类型,可以查看相关内容

//-|structure define|-
struct timespec{
     time_t   tv_sec;//秒数
     long     tv_nsec;//不足一秒的纳秒数
};

//--set-- 下面的函数将用来获取或者设置实时时钟
(131)、int clock_getres(clockid_t clock_id,struct timespec* res) //该函数将返回指定时钟的分辨率,保存在res里面
(132)、int clock_gettime(clockid_t clock_id,struct timespec* tp) //返回指定实时时钟的时间,保存在tp里面
(133)、int clock_settime(clockid_t clock_id,const struct timespec* tp) //设置实时时钟,只有特权用户可以
/一种时间更短的睡眠/
(134)、int nanosleep(const struct timespec* res,struct timespec* rem) //睡眠res时间,如果有信号来了,将剩余时间保存在rem里面
//--comment-- 实时定时器,分辨率更高

//-|structure define|-
struct itimerspec
{
     struct timespec it_value;//定时开始时间
     struct timespec it_interval;//定时间隔
}

//--set-- 下面的函数将实现创建和删除实时定时器
(135)、int timer_create(clockid_t clockid,struct sigevent* restrict evp/action/,timer_t restrict timerid/id of timer*/)
(136)、int timer_delete(timer_t timeid) //delete a timer

//--set-- set and get timer
(137)、int timer_gettimer(timer_t timeid,struct itimerspec* value) //get
(138)、int timer_settimer(timer_t timeid,int flags,const struct itimerspec* restrict value,struct itimerspec* restrict ovalue)
(139)、int timer_getoverrun(timer_t timeid) //返回定时器的超时次数
/这个函数在前面已经有介绍,但是这里作为设置文件锁而特别指出/
(140)、int fcntl(int fildes,int cmd,struct flock* lock)
/*
关于信号驱动的IO:采用信号驱动的IO,则当在描数字上有数据到达时,进程会收到一个信号,此时对
该描数字进行输入输出操作将不会被阻塞。
下面是实现信号驱动的IO的步骤:
(1)、调用sigaction函数来建立信号句柄
(2)、调用fcntl函数用F_SETOWN来设置接收信号的进程或者进程组
(3)、如果要接收的信号是SIGIO,需要调用fcntl函数用F_SETTFL命令设置文件描数字的O_ASYNC标志使其能够生成SIGIO信号
/
/
下面这个函数功能很强大,他告诉内核,需要等待多种IO事件,只有当这些中的一个或者多个出现时,或者指定的时间过去时,才唤醒调用他的进程/
(141)、int select(int nfds,fd_set
rfds,fd_set* wfds,fd_set* efds,struct timeval* timeout)

    关于上面这个函数,函数将返回已经就绪的描数字的个数,或者超时出返回-1
    我们可以用下面的宏定义来查看一些细节:
    void FD_ZERO(fd_Set* fdset)    //初始化为空
    void FD_CLR(int filedes,fd_Set* fdset) //将filedes从fdset里面清除
    void FD_ISSET(int filedes,fd_set* fdset) //属于吗
    void FD_SET(int filedes,fd_set* fdset) //加入

/下面这个函数和select函数一样,检查一组文件描数字,查看是否有任何悬挂的事件,并且可以有选择的为某个描数字上的时间设定时间/
(142)、int poll(struct pollfd fds[],nfds_t nfds,int timeout)

//-|structure define|-
struct pollfd{
    int fd;//要检查的描数字
    short events;//感兴趣的事情
    short revents;//fd上发生的事情
};
/*
   * events 是用户对这个文件描数字上感兴趣的事情,而revents是这个文件描数字上实际发生的事件。
   * 也就是函数的返回值,最后一个参数为最长的等待时间,单位时毫秒
*/

/*下面这个函数可以将一个文件映射到内存,应当首先用open打开,然后调用下面这个函数*/

(143)、void* mmap(void* addr,size_t len,int prot,int flags,int filedes,off_t off)
///--- 上面函数实现将指定文件描数字filedes中的文件的[off,off+len]区间映射到进程的内存
///--- [paddr,paddr+len]区间,paddr是函数的返回值。也就是最终的映射到进程的开始地址
///--- 那么addr是什么玩意呢?也就是自己指定映射的开始位置,如果为0,那么内核将找到合适的
///--- 位置然后告诉进程我把文件映射到了哪里!
///--- 其中,prot是映射区的保护权限,应该和open时指定的权限一致。
///--- flags是映射区的属性,必须要么是共享的,要么是私有的,还可以加上是否必须返回addr

/当然,有映射自然会有解映射,下面这个函数是,mmap的相反函数/
(144)、int mumap(void* paddr,size_t len)
///--- paddr应该是mmap返回的结果,len是映射区的长度。

/对于属性为共享的存储映射区,当映射区的一页被修改时,会被存回硬盘,如果想要在程序的某个点将其中的内容写到磁盘,下面这个函数可以/
(145)、 int msync(void* addr,size_t len,int flags)
///--- flags参数控制写回这片区域的执行方式,可以取下面三个
///--- MS_ASYNC -->异步执行
///--- MS_SYNC -->同步执行,完成函数才会返回
///--- MS_INVALIDATE -->作废与指定映射区中的数据不一致的缓存副本

/下面这个函数用来创建一根管道,函数将返回两个文件描数字,分别是管道的输入输出端/
(146)、int pipe(int fildes[2])
///--- fildes[0] 将设置为读而打开,dildes[1]将设置为写而打开
///--- 管道是没有名字的,所以叫做匿名管道

/下面这个函数关于在调用进程与要执行的命令之间建立一个内部的半双工的管道,然后派生一个子进程,执行command命令/
///--- 需要注意是,这和system函数还是有区别的,system函数将等待执行完成再返回,而该函数将立即返回
(147)、FILE* popen(const char* command,const char* mode)
/用popen打开的管道需要用下面的函数来关闭/
(148)、int pclose(FILE* stream)
///--- 管道只能用于父子进程之间的通信,因为管道建立在内核之中,只有那些有遗传关系的进程才能用到它
///--- FIFO特别文件可以在非父子关系的进程之间实现数据交换
///--- 对于FIFO特别文件来说,只要文件被打开,他的行为就和管道是一样的。
///--- 在进行通信之前,需要有一个进程以读打开这个fifo文件,另一个进程以写打开这个fifo特别文件
/这个函数将创建一个名字为filename的fifo文件/
(149)、int mkfifo(const char* filename,mode_t mode)
/这个函数更加强大,不仅可以创建fifo文件,还可以创建其他的文件,文件类型由mode给出/
(150)、int mknod(const char* filename,mode_t mode,dev_t dev)
/下面这个函数可以用来创建获得消息队列,函数调用成功会返回与key相连的id,我们可以用id来访问消息队列/
(151)、int msgget(key_t key,int flags)
/消息队列的查询、设置和删除/
(152)、 int msgctl(int msqid,int cmd,struct msqid_ds* buf)
///--- cmd 就是我们想要做的事情,可以取下面的值---
///--- IPC_STAT --> 复制消息队列的内核数据结构到buf里面
///--- IPC_SET -->用buf里面的值设置消息队列
///--- IPC_RMID --> 删除指定的消息队列

/下面这个函数实现向一个消息队列发送消息/
(153)、 int msgsnd(int msqid,const void* msgp,size_t msgze,int msgflg)
///--- 第一个参数是消息队列的id,第二个参数是指向消息缓冲区的指针,第三个参数给出消息缓冲区的消息正文的字节数
///--- 不包括消息类型成员(第一个成员),最后一个参数用来引导当进程阻塞时的动作

/下面这个函数用来接收消息/
(154)、ssize_t msgrcv(int msqid,void* msgp,size_t msgsz,long int msgtyp,int msgflg)
///---这个函数从消息队列msqid里面读消息到msgp里面,msgsz指出消息正文的字节数,msgtyp指明要接收的消息类型
///--- --> =0 接收消息队列里面的第一个消息
///--- --> >0 接收类型等于msgtyp的第一个消息,这种方式可实现只接收特定类型的消息
///--- --> <0 接收类型小于或者等于msgtyp绝对值的第一个最低类型的消息,实现优先级

/下面这个函数将实现创建和获得共享存储段/
(155)、int shmget(key_t key,size_t size,int shmflg)
/共享存储段的查询、设置、删除/
(156)、int shmctl(int shmid,int cmd,struct shmid_ds* buf)
/创建好了共享存储段之后,我们还需要将它映射到进程的地址空间,下面这个函数可以实现这个功能/
(157)、void* shmat(int shmid,const void* shmaddr,int shmflg)
///--- 温馨提示:为了简单,shmaddr就让他等于0吧,剩下的事情让操作系统为你完成
/创建和获得信号量/
(158)、int semget(key_t key,int nsems,int semflg)
///--- nsems指明信号量集合中信号量的个数
/信号量的查询、设置、删除/
(159)、int semctl(int semid,int semnum,int cmd,[union semun arg])
///--- semid是信号量集合的标志,semnum指明一个特定的信号量
/信号量操作/
(160)、int semop(int semid,struct sembuf* sops,size_t nsops)
///--- 该函数对指定的semid信号量集合进行操作,操作既可以对其中的一个信号量,也可以针对整个信号量还可以
///--- 是等待信号量,sops给出操作类型

//-|structure define|-
struct sembuf
{
    unsigned short int sem_num;//信号量编号
    short int sem_op;//信号量操作
    short int sem_flg;//信号量标志
}

///--- sem_op
///--- <0 减少一个信号量,减少的值为abs(sem_op),当为-1时,相当于P操作
///--- >0 增加一个信号量,增加的值为sem_op,当为1时,相当于V操作
///--- ==0 等待信号量变为0
///--- 注意:semop()函数调用只有当集合中所有信号量都能成功时才成功返回,如果某个信号量不能完成,失败!

//套接字等价于网络,就好像文件描数字是磁盘描述的一个端口一样。我们可以用下面的函数来创建一个网络套接字
(161)、int socket(int domain,int type,int protocol)
///---socket 将和文件描数字一样会返回最小的还没有被使用的套接字描数字
///---第一个参数domain指明通信域:可以为AF_UNIX,AF_INET,AF_INET6
///---第二个参数是套接字的类型,可以为:SOCK_STREAM,SOCK_DGRAM,SOCK_RAW.
///---对于第三个参数,只要前两个参数确定了,就可以确定第三个参数也就是协议了,所以只需要填0就可以了

/下面的函数可以实现同时创建一对套接字描数字,是全双工的/
(162)、int socketpair(int domain,int type,int protocol,int filedes[])

/下面这个函数用来关闭一个已经打开的套接字描数字,党我们关闭了一个套接字之和,这个套接字便不再存在/
(163)、int close(int socket)
/当我们这是想断开连接而不是关闭一个套接字,那么可以用下面这个函数来实现/
(164)、int shutdown(int socket,int how)
///---这个函数将部分或者全部断开套接字socket的连接,取决于how的值是什么
///---SHUT_RD:停止从该套接字接收数据
///---SHUT_WR:停止从该套接字传送数据
///---SHUT_RDWR:停止从该套接字传输和接收数据

/下面这组函数将实现ip地址的格式转换,可以从二进制形式转换为点分十进制形式,也可以向相反的方向转换/
(165)、int inet_aton(const char* name,struct in_addr* addr) //从字符串转换到二进制(32位),保存在addr里面
(166)、char* inet_ntoa(struct in_addr* addr)//将32位的ip地址转换为字符串形式
(167)、int inet_pton(int family,const charnameptr,void addrptr) //将可以用在ipv4上,也可以用在ipv4上
(168)、const char* inet_ntop(int family,void* addptr,char* nameptr,size_t len)

//在unix里面,用了一个主机网络地址数据库来记住主机名和主机ip地址之间的映射
//我们可以用下面的函数来从这个数据库中获得一台主机的完整地址信息
(168)、struct hostent* gethostbyname(const char* name)
(169)、struct hostent* gethostbyaddr(const void* addr,size_t length,int type) //length is the len of addr,the type is the type of addr

/我们可以用下面的这个函数来打开地址数据库,当参数为不为0时,将会和数据库建立持久连接/
(170)、void sethostent(int stayopen)
(171)、struct hostent* gethostent();
(172)、void endhostent(); //关闭数据库

///--我们知道有一些默认的应用是绑定到了固定的端口上的,比如21号端口就是用来进行FTP服务的,我们
///---可以通过下面的函数来查看一些著名的服务
(173)、struct servent* getservbyname(const char* name,const char* proto)
(174)、struct servent* getservbyport(int port,const char* proto)
(175)、void setservent(int stayopen)
(176)、struct servent* getservent();
(177)、void endservent()

///---下面是很烦很无聊的字节顺序转换,在网络上操作的话都要转换为网络字节顺序
(178)、uint_16_t htos(uint_16_t hostshort)
(179)、uint_32_t htol(uint_32_t hostlong)
(180)、uint_16_t stoh(uint_16_t hostshort)
(181)、uint_32_t ltoh(uint_32_t hostlong)

///---好吧,现在我们应该会创建一个套接字描数字,然后也了解了ip地址,套接字等内容,下面我们需要给套机字一个名字
///---当套接字有了名字之和,我们就可以使用套机字名字来操作这个套机字了,也就是说,套机字没有名字,其他进程根本
///---无法访问到这个没有名字的套接字,所以我们需要给他一个名字,下面这个函数可以实现将一个套接字绑定在一个名字上
(182)、int bind(int socket,const struct sockaddr* address,socklen_t address_len)

///---现在我们先来了解一下套机字是怎么工作的:首先用socket函数创建一个套接字描数字,然后调用bind函数来给
///---这个套接字绑定一个名字,以便其他进程可以访问这个套接字。然后用listen来监听这个套接字上的活动,在多个
///---客户与该套接字建立连接的情况下,listen函数为进入该套接字的连接创建一个连接队列,然后调用accept函数
///---逐一处理这些连接,需要知道的是,每次调用accept函数,系统都将创建一个新的套接字,但是这个新的套接字将
///---只用于与特定的客户连接,所以不需要命名,那已经命名的套接字保留用于与其他用户连接,这样就可以实现
///---一个套接字描数字和多个客户通信的需求了---->以上言论对有连接的套接字通信有效
///---对于无连接的套接字通信,事情变得很简单,他使用对等的方式来进行数据交换,但是依然需要bind一个名字
///---然后事情就在recvfrom和sendto这两个函数之间变得有趣了!

//下面这个函数是对于流套接字操作而言的,而且这个函数用于客户端请求与服务端建立一个连接
(183)、int connect(int socket,const struct sockaddr* address,socklen_t address_len)

//下面函数可以在套接字上创建侦探队列,成功后这个套接字将称为被动套接字,也就是服务套机字
(184)、int listen(int socket,int backlog) //backlog指明该套接字上可以悬挂的请求连接数

//下面函数将会创建一个新的套机字来为客户服务,函数将返回新套接字的描数字,后两个参数将作为返回
(185)、int accept(int socket,struct sockaddr* address,socklen_t* address_len)

//两个套接字建立连接之和,我们可以通过下面的函数来查看对方套机字地址和本地套机字地址
(186)、int getsockname(int socket,struct socketaddr* address,socklen_t* address_len) //获取本地
(187)、int getpeername(int sock,struct sockaddr* address,socklen_t* address_len) //获取对方的

/我们应该知道,套接字也是一种文件,所以可以像操作文件一样操作套接字,write和read可以用来从一个套接字读取数据和发送数据/
///---下面的函数也可以实现向一个套接字发送数据或者从套接字读取数据
(188)、ssize_t send(int socket,const void* buffer,size_t length,int flags)
///---需要注意的是最后一个参数,如果最后一个参数为0,那么就和write一样了,当然这个标志可以取下面的值
///---MSG_OOB:使得send发送的数据称为带外数据
///---MSG_DONTROUTE:不再消息中包含路由信息
(189)、ssize_t recv(int socket,void* buffer,size_t length,int flags)
///---最后一个参数要是取0的话,和read是一样的
///---MSG_PEEK:窥视套接字上的数据但是不读取他们
///---MSG_OOB:读带外数据
///---MSG_WAITALL:函数将阻塞直到读到所请求的全部数据

/下面的函数将可以查看和设置套接字的各自选项/
(190)、int getsockopt(int socket,int level,int optname,void* optval,socklen_t* optlen)
(191)、int setsockopt(int socket,int level,int optname,const void* optval,socklen_t optlen)

///---需要注意的是,参数socket需要是已经打开的套接字,level指出所选择的层次,可以是下面的值
///---SOL_SOCKET,IPPOTO_IP,IPPOTO_TCP
///---optname指出选项的名字,对于getsockopt来说,函数将读取名字为optname的选择,将读出来的值
///---保存在optval里面,对于设置来说,需要自己指定optval
///---选项可以查看相应的文档获得

/下面这个函数可以判断当前是否处在带外数据标志的位置/
(192)、int sockatmark(int sockfd)
///---(1)、当下一个要读的字节是oob时,函数返回真
///---(2)、读操作总是停止在带外数据标志之处

/下面这两个函数可以实现对数据报套接字的数据发送与接收/
(193)、int recvfrom(int socket,void* buffer,size_t size,int flags,struct sockaddr* from,size_t* addrlen)
(194)、int sendto(int socket,void* buffer,size_t size,int flags,struct sockaddr* to,size_t addrlen)

///---需要特别说明,数据报套接字也可以使用connect函数,但是对于数据报套接字来说这个函数并不会建立连接
///---而只是给将来在此套接字上的传送指定地址,内核将记录对等套接字的ip地址和端口,这样我们就可以不用
///---recvfrom和sendto函数了,可以使用read或者recv或者write或者send函数了

/下面的函数可以查看一个线程自己的线程id,需要知道的是线程也有线程id,而且在一个进程里面的每一个线程都具有不一样的线程id/
(195)、pthread_t pthread_self()

/下面这个函数可以用来比较俩个线程id,两个线程id相同时返回非0,不同时返回0/
(196)、int pthread_equal(pthread_t t1,pthread_t t2)

/下面这个函数用来创建一个新的线程/
(197)、int pthread_create(pthread_t restrict thread,const pthread_attr_t restrict attr,
void(start_routine)(void),void restrict argv)

///---每一个进程一开始就会有一个线程,称为初始线程,或者叫做主线程,他是从main函数开始的,进程中的其他
///---线程在创建线程时指定一个线程开始函数,这个线程开始函数只能有一个void*的参数,这个新创建的线程将
///---从这个函数开始执行
///--第一个参数是函数的返回值,函数调用成功将返回这个新创建的线程的id,第二个参数指定新创建的线程的属性

/下面这个函数将终止线程,也就是终止自己的执行/
(198)、int pthread_exit(void* value_ptr)

///---参数应该是一个出口状态,当其他的线程在等待这个线程时,当这个线程结束时,其他等待该线程的线程将会得到这个
///---线程出口状态,然后做下一步的动作

/下面这个函数用来等待一个线程终止/
(199)、int pthread_join(pthread_t thread,void** value_ptr)

///---该函数将悬挂调用该函数的线程直到所等待的线程终止,第二个参数将保存从等待线程返回的出口状态,该
///---线程可以根据这个出口状态来执行相应的函数

///---关于可汇合线程和分离线程
///---可汇合线程:线程的资源需要另一个线程调用pthread_join与他汇合之后才能被释放
///---分离线程:线程一旦终止,系统将立刻回收他的资源

/下面的函数可以将原本可汇合的线程变为分离的线程,需要知道的是,默认创建的线程都是可汇合的/
(200)、int pthread_detach(pthread_t thread)
///---已经分离的线程不能和其他线程汇合,所以一旦一个线程被设置为分离的,那么这个线程就不能被pthread_join

/下面的一组函数用来设置特殊属性的线程/

///---线程的一般属性包括:分离状态属性,栈的大小,栈地址,栈溢出保护区大小,调度属性,调度的竞争范围,调度的继承属性
///---调度策略,调度参数
(201)、int pthread_attr_init(pthread_attr_t attr) //初始化一个线程属性
(202)、int pthread_attr_destroy(pthread_attr_t
attr) //销毁一个线程属性对象
(203)、int pthread_attr_getdetachstate(pthread_attr_t* attr,int* detachstate) //查询线程属性对象的分离状态,将返回在第二个参数里面
(204)、int pthread_attr_setdetachstate(const pthread_ttr_t* attr,int detachstate) //设置线程属性属性对象的分离状态

///---下面是互斥变量的初始化和销毁
(205)、pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
(206)、int pthread_mutex_init(pthread_mutex_t restrict mutex,const pthread_mutexattr_t restrict attr) //初始化
(207)、int pthread_mutex_destroy(pthread_mutex_t *mutex)

///---互斥变量也是有属性的,现在有两种属性,一种是进程共享属性,和类型属性
///---共享属性设置一个互斥锁是否可以在进程之间使用
///---下面的函数是和互斥变量属性相关的函数
(208)、int pthread_mutexattr_init(pthread_mutexattr_t * attr) //初始化一个互斥变量属性
(209)、int pthread_mutexattr_destroy(pthread_mutexattr_t* attr) //销毁一个互斥变量属性

///---下面两组函数可以用来设置互斥变量的进程共享属性和类型属性
(210)、int pthread_mutexattr_setpshared(pthread_mutexattr_t* attr,int pshared) //设置进程共享属性
(211)、int pthread_mutexattr_getpshared(pthread_mutexattr_t* attr,int *restrict pshared) //查看互斥变量的进程共享属性

(212)、int pthread_mutexattr_settype(pthread_mutexattr_t* attr,int pshared) //设置互斥变量类型属性
(213)、int pthread_mutexattr_hettype(pthread_mutexattr_t* attr,int * restrict type)

///--下面的函数用来对互斥变量加锁或者解锁
(214)、int pthread_mutex_lock(pthread_mutex_t* mutex) //上锁,但是如果失败,等待直到获得锁才返回
(215)、int pthread_mutex_trylock(pthread_mutex_t* mutex)//如果上锁失败的话,立刻返回错误<EBUSY>
(216)、int pthread_mutex_unlock(pthread_mutex_t* mutex)//解锁

///---下面的函数是和spin锁相关的函数,操作和理解方式和互斥锁一样
(217)、int pthread_spin_init(pthread_spinlock_t * lock,int pshared) //初始化一个spin
(218)、int pthread_spin_destroy(pthread_spinlock_t* lock)
(219)、int pthread_spin_lock(pthread_spinlock_t* lock)
(220)、int pthread_spin_trylock(pthread_spinlock_t* lock)
(221)、int pthread_spin_unlock(pthread_spinlock_t* lock)

///---需要注意的是,spin锁和互斥锁还是不一样的,当上锁受阻时,线程不需要阻塞而是可以轮询直到获得锁

///---下面的函数是关于读写锁的
///---读写锁支持线程对数据的共享读互斥写
///---可以以读方式上锁,一个线程占有这个锁之后,还是允许其他的线程来以读的方式上锁
///---可以以写方式上锁,一个线程占有这个锁之后,不允许其他的锁进来
(222)、pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALZER;
(223)、int pthread_rwlock_init(pthread_rwlock_t* restrict rwlock,const pthread_rwlockattr_t* attr)
(224)、int pthread_rwlock_destroy(pthread_rwlock_t* rwlock)
///---需要注意的是,读写锁只有一种属性,可以指定为进程之内或者是进程之间
///---下面的函数是关于读写锁属性的函数
(225)、int pthread_rwlockattr_init(pthread_rwlockattr_t* attr)
(226)、int pthread_rwlockattr_destroy(pthread_rwlockattr_t* attr)
(227)、int pthread_rwlockattr_setpshared(pthread_rwlockattr_t* attr,int pshared)
(228)、int pthread_rwlockattr_getpshared(pthread_rwlockattr_t* attr,int pshared)

///---下面的函数是关于读写锁的上锁和解锁的
(229)、int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) //以读方式上锁,如果不能获得锁,那么受阻直到获得锁
(230)、int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) //如果线程不能立刻获得锁的话,那么这个函数将会返回EBUSY<立刻>

(231)、int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock)
(232)、int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock)

///---无论读写锁是怎么加的锁,下面这个函数都可以解开
(234)、int pthread_rwlock_unlock(pthread_rwlock_t* rwlock)

///---关于条件变量
///---下面的函数是关于初始化和销毁条件变量的
(235)、pthread_cond_t cond=PTHREAD_COND_INITIALZER;
(236)、int pthread_cond_init(pthread_cond_t* cond,pthread_condattr_t* attr)
(237)、int pthread_cond_destroy(pthread_cond_t* cond)

///---条件变量的属性操作函数集合
(238)、int pthread_condattr_init(pthread_condattr_t* attr)
(239)、int pthread_condattr_destroy(pthread_condattr_t* attr)
(240)、int pthread_condattr_setpshared(pthread_condattr_t* attr,int * pshared)
(241)、int pthread_condattr_getpshared(pthread_condattr_t* attr, int * pshared)

///---等待条件变量
///---一个是执行正常的等待操作,一个是指定定时的等待操作
(242)、int pthread_cond_wait(pthread_cond_t* cond,pthread_mutex_t* mutex)//mutex是与条件变量相关连的互斥变量
(243)、int pthread_cond_timedwait(pthread_cond_t* cond,pthread_mutex_t* mutex,struct timespec* abstime)
///---需要注意的是,调用这两个函数之前mutex必须处于锁住的状态,在这两个函数阻塞之前,函数将会释放mutex

///---唤醒条件变量的等待,可以有两种方式来唤醒,一种是每次唤醒一个线程,称为“发信号”
///---另一种则一次唤醒等待在同一个条件变量上的所有线程,这种方式称为“广播”
(244)、int pthread_cond_signal(pthread_cond_t* cond)
(245)、int pthread_cond_broadcast(pthread_cond_t* cond)
///---如果没有线程等待在条件变量cond上面,那么这个两个函数将没有任何作用

///---关于线程专有数据键
(246)、int pthread_key_create(pthread_key_t * key,void(destrcutor)(void)) //函数返回在key里面
///---创建键的作用只是为每一个线程相连一个指向其专有存储空间的指针,这些指针的初始值都是null,key一旦
///---创建成功,那么就可以通过函数pthread_getspecific()使之指向各自分配的专有数据存储空间
///---第二个参数是一个析构函数,这个函数负责在线程终止时做一些回收工作,所以当线程终止时,线程会查看
///---线程专有数据键,如果上面有安装析构函数的话,那么就执行这个析构函数
///---需要注意的是,线程专有数据键只能由一个线程创建一次,如果多次创建,会丢失数据
///---下面这个函数可以保证一个专有数据键只创建一次
(247)、pthread_once_t once_control=PTHREAD_ONCE_INIT;
(248)、int pthread_once(pthread_once_t* once_control,void(*init_routine)(void))
///---第二个参数是一个初始化参数,pthread_once函数会记录这个初始化函数是否已经被调用,如果已经被调用
///---那么任何调用pthread_once函数创建的数据key都将以失败返回
///---下面的函数可以用来删除一个专有数据键
(249)、int pthread_key_delete(pthread_key_t key)

///---对于每一个线程,当线程专有数据键创建时,都是null的,为了使用线程专有数据键,每一个线程需要给专有数据键指定值
///---线程专有数据键是全局的,线程内的所有函数都能访问,但是每一个线程与键相连的存储空间是独立的,因此,他们是私有的
///---也就是,他们是对线程私有的全局数据
///---下面的函数用来设置线程的专有数据和访问线程专有数据
(250)、int pthread_setspecific(pthread_key_t key,const void* value) //设置value为调用线程的线程专有数据键key
(251)、void *pthread_getspecific(pthread_key_t key)//获得键key对应于调用线程的专有数据

///---线程与信号
///---在多线程的情况下,信号屏蔽不再是整个进程只有一个,而是每个线程一个
///---虽然所以线程共享相同的信号动作,但是每个线程可以阻塞自己不想处理的信号
///---下面的函数用来设置信号屏蔽
(252)、int pthread_sigmask(int how,const sigset_t* set,sigset_t* oldset)
///---how->
///---SIG_BLOCK:将set添加进来
///---SIG_UNBLOCK:将set移除
///---SIG_SETMASK:替换原来的

///---下面的函数用来向线程发送信号
///---线程向进程发送信号任然使用kill
(253)、int pthread_kill(pthread_t thread,int aigno)
///---线程可以用下面的方式向自己发送信号
pthread_kill(pthread_self(),sig) or raise(sig)

///---等待信号,在接收到信号之后直接对信号进行处理,而不需要信号句柄
///---该函数将阻塞调用线程直到出现set里面的信号,sig会返回信号数量
(254)、int sigwait(const sigset_t* set,int * sig)

///---要注意的是,在线程调用sigwait之前,所有线程都应当阻塞了信号集set中的信号,否则会导致不可预测的结果

/--2016/4/16--hujian--/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343