学习笔记:如何使用Linux下的pid_t数据类型 (linux下pid_t)

Linux是一种开放源代码的操作系统,其内核由许多模块组成。其中一个非常有用的模块就是进程。在Linux中,进程是用来执行程序的一种单位,每一个进程都有一个唯一的进程ID(pid),该ID通过pid_t数据类型来表示。在Linux系统的开发和调试过程中,熟练掌握pid_t数据类型的使用是非常必要的。

1. pid_t数据类型的定义

在Linux中,pid_t数据类型是由头文件中定义的。其定义如下所示:

typedef __pid_t pid_t;

其中,__pid_t是由内核使用的原始pid_t类型,pid_t是标准库中使用的数据类型。

2. pid_t数据类型的特点

pid_t数据类型有以下几个特点:

(1) pid_t是一个有符号整数类型,其取值范围通常是在-2^31到2^31-1之间,即32位操作系统。

(2) pid_t数据类型可以用来表示Linux系统中的进程ID,进程ID是系统内部使用的一个唯一标识符,用于标识系统中正在运行的进程。

(3) pid_t数据类型也可以用来表示由Linux内核分配的系统资源的ID,例如系统内部的打印机队列ID、消息队列ID、信号量ID等等。

3. pid_t数据类型的使用方法

pid_t数据类型主要用于两个函数的参数传递:

(1) fork()函数

fork()函数用来创建一个新的进程,该进程从调用fork()函数的进程中复制过来。fork()函数的返回值是一个pid_t类型的整数值,该值可以用来区分父进程和子进程。如果返回值是负数,则表示创建新进程失败。如果返回值为0,则表示进程是子进程。如果返回值是正整数,则表示进程是父进程。父进程的返回值是子进程的进程ID。子进程的返回值是0。

下面是一个简单的fork()函数的使用示例:

pid_t pid = fork();

if(pid

//创建进程失败

}else if(pid == 0){

//子进程

}else{

//父进程

}

(2) wt()函数

wt()函数用来等待子进程结束,等待子进程结束后可以获取该进程的状态信息。wt()函数的返回值是pid_t类型的整数值,该值表示子进程的进程ID。如果没有子进程,则wt()函数返回-1。

下面是一个简单的wt()函数的使用示例:

pid_t pid = fork();

if(pid

//创建进程失败

}else if(pid == 0){

//子进程

}else{

//父进程

int status;

wtpid(pid, &status, 0);

//获取子进程的状态信息

}

4.

相关问题拓展阅读:

在linux中兑现ping部分功能怎么解决

运用C语言编写模拟常用网络命令ping命令实现一个基于linux原始套接字和ICMP协议的ping程序。该辩隐程序能用于检测主机或路由器工作是否正常。

程序中主要的函数

void alarm_handler(int); /*SIGALRM处理程序*/

void int_handler(int); /*SIGINT处理程序*/

void set_sighandler(); /*设茄漏置信号处理程序*/

void send_ping(); /*发送ping消息*/

void recv_reply(); /*接收ping应答*/

u16 checksum(u8 *buf, int len); /*计算校验和*/

int handle_pkt(); /*ICMP应答消息处理*/

void get_statistics(int, int); /*统计ping命令的检测结果*/

void bail(const char *); /*错误报告*/

头文件:ping.h

#define ICMP_ECHOREP 0 /* Echo应答*/

#define ICMP_ECHO /*Echo请求*/

#define BUFSIZE/*发送缓存更大值*/

#define DEFAULT_LEN 56 /**ping消息数据默认大小/

/*数据类型别名*/

typedef unsigned char u8;

typedef unsigned short u16;

typedef unsigned int u32;

/*ICMP消息头部*/

struct icmphdr {

u8 type; /*定义消息类型*/

u8 code; /*定义消息代码*/

u16 checksum; /*定义校验*/

union{

struct{

u16 id;

u16 sequence;

}echo;

u32 gateway;

struct{

u16 unsed;

u16 mtu;

}frag; /*pmtu实现*/

}un;

/*ICMP数据占位符*/

u8 data;

#define icmp_id un.echo.id

#define icmp_seq un.echo.sequence

};

#define ICMP_HSIZE sizeof(struct icmphdr)

/*定义一个IP消息头部结构体*/

struct iphdr {

u8 hlen:4, ver:4; /*定义4位首部长度,和IP版本号为IPV4*/

u8 tos;/*8位服务类型TOS*/

u16 tot_len; /*16位总长度*/

u16 id;/*16位标志位*/

u16 frag_off; /*3位标志位*/

u8 ttl;/*8位生存周期*/

u8 protocol; /*8位协议*/

u16 check;/*16位IP首部校验和*/

u32 saddr;/*32位源IP地址*/

u32 daddr;/*32位目的IP地址*/

};

char *hostname;/*被ping的主机名*/

int datalen = DEFAULT_LEN; /*ICMP消息携带的数据长度*/

char sendbuf;/*发送字符串数组*/

char recvbuf;/*接收字携纳厅符串数组*/

int nsent;/*发送的ICMP消息序号*/

int nrecv;/*接收的ICMP消息序号*/

pid_t pid;/*ping程序的进程PID*/

struct timeval recvtime; /*收到ICMP应答的时间戳*/

int sockfd;/*发送和接收原始套接字*/

struct sockaddr_in dest; /*被ping的主机IP*/

struct sockaddr_in from; /*发送ping应答消息的主机IP*/

struct sigaction act_alarm;

struct sigaction act_int;

/*函数原型*/

void alarm_handler(int); /*SIGALRM处理程序*/

void int_handler(int);/*SIGINT处理程序*/

void set_sighandler();/*设置信号处理程序*/

void send_ping();/*发送ping消息*/

void recv_reply();/*接收ping应答*/

u16 checksum(u8 *buf, int len); /*计算校验和*/

int handle_pkt();/*ICMP应答消息处理*/

void get_statistics(int, int); /*统计ping命令的检测结果*/

void bail(const char *); /*错误报告*/

源程序2:ping.c

#include

#include

#include /*是Linux系统的日期时间头文件*/

#include /* 是POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型,例如read函数、write函数和getpid函数*/

#include

#include /*对与引用socket函数必须*/

#include

#include /*定义了与网络有关的结构,变量类型,宏,函数。函数gethostbyname()用*/

#include /*sys/types.h中文名称为基本系统数据类型*/

#include /*inet_ntoa()和inet_addr()这两个函数,包含在 arpa/inet.h*/

#include /*进程对信号进行处理*/

#include /*互联网地址族*/

#include”ping.h”

#define IP_HSIZE sizeof(struct iphdr) /*定义IP_HSIZE为ip头部长度*/

#define IPVERSION 4 /*定义IPVERSION为4,指出用ipv4*/

/*设置的时间是一个结构体,倒计时设置,重复倒时,超时值设为1秒*/

struct itimerval val_alarm={.it_interval.tv_sec = 1,

.it_interval.tv_usec=0,

.it_value.tv_sec=0,

.it_value.tv_usec=1

};

int main(int argc,char **argv) /*argc表示隐形程序命令行中参数的数目,argv是一个指向字符串数组指针,其中每一个字符对应一个参数*/

{

struct hostent *host; /*该结构体属于include*/

int on =1;

if(argc中,地址族*/

dest.sin_port=ntohs(0); /*端口号,ntohs()返回一个以主机字节顺序表达的数。*/

dest.sin_addr=*(struct in_addr *)host->h_addr_list;/*host->h_addr_list是地址的指针.返回IP地址,初始化*/

if((sockfd = socket(PF_INET,SOCK_RAW,IPPROTO_ICMP))hlen=sizeof(struct iphdr)>>2; /*头部长度*/

ip_hdr->ver=IPVERSION; /*版本*/

ip_hdr->tos=0; /*服务类型*/

ip_hdr->tot_len=IP_HSIZE+ICMP_HSIZE+datalen; /*报文头部加数据的总长度*/

ip_hdr->id=0; /*初始化报文标识*/

ip_hdr->frag_off=0; /*设置flag标记为0*/

ip_hdr->protocol=IPPROTO_ICMP;/*运用的协议为ICMP协议*/

ip_hdr->ttl=255; /*一个封包在网络上可以存活的时间*/

ip_hdr->daddr=dest.sin_addr.s_addr; /*目的地址*/

len1=ip_hdr->hlentype=8; /*初始化ICMP消息类型type*/

icmp_hdr->code=0; /*初始化消息代码code*/

icmp_hdr->icmp_id=pid; /*把进程标识码初始给icmp_id*/

icmp_hdr->icmp_seq=nsent++; /*发送的ICMP消息序号赋值给icmp序号*/

memset(icmp_hdr->data,0xff,datalen); /*将datalen中前datalen个字节替换为0xff并返回icmp_hdr-dat*/

gettimeofday((struct timeval *)icmp_hdr->data,NULL); /* 获取当前时间*/

len=ip_hdr->tot_len; /*报文总长度赋值给len变量*/

icmp_hdr->checksum=0; /*初始化*/

icmp_hdr->checksum=checksum((u8 *)icmp_hdr,len); /*计算校验和*/

sendto(sockfd,sendbuf,len,0,(struct sockaddr *)&dest,sizeof (dest)); /*经socket传送数据*/

}

/*接收程序发出的ping命令的应答*/

void recv_reply()

{

int n,len;

int errno;

n=nrecv=0;

len=sizeof(from); /*发送ping应答消息的主机IP*/

while(nrecv1){

sum+=*cbuf++;

len-=2;

}

if(len)

sum+=*(u8 *)cbuf;

sum=(sum>>16)+(sum & 0xffff);

sum+=(sum>>16);

return ~sum;

}

/*ICMP应答消息处理*/

int handle_pkt()

{

struct iphdr *ip;

struct icmphdr *icmp;

int ip_hlen;

u16 ip_datalen; /*ip数据长度*/

double rtt; /* 往返时间*/

struct timeval *sendtime;

ip=(struct iphdr *)recvbuf;

ip_hlen=ip->hlen tot_len)-ip_hlen;

icmp=(struct icmphdr *)(recvbuf+ip_hlen);

if(checksum((u8 *)icmp,ip_datalen)) /*计算校验和*/

return -1;

if(icmp->icmp_id!=pid)

return -1;

sendtime=(struct timeval *)icmp->data; /*发送时间*/

rtt=((&recvtime)->tv_sec-sendtime->tv_sec)*1000+((&recvtime)->tv_usec-sendtime->tv_usec)/1000.0;/* 往返时间*/

/*打印结果*/

printf(“%d bytes from %s:icmp_seq=%u ttl=%d rtt=%.3f ms\n”,

ip_datalen, /*IP数据长度*/

inet_ntoa(from.sin_addr), /*目的ip地址*/

icmp->icmp_seq, /*icmp报文序列号*/

ip->ttl, /*生存时间*/

rtt); /*往返时间*/

return 0;

}

/*设置信号处理程序*/

void set_sighandler()

{

act_alarm.sa_handler=alarm_handler;

if(sigaction(SIGALRM,&act_alarm,NULL)==-1) /*sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum指所要捕获信号或忽略的信号,&act代表新设置的信号共用体,NULL代表之前设置的信号处理结构体。这里判断对信号的处理是否成功。*/

bail(“SIGALRM handler setting fails.”);

act_int.sa_handler=int_handler;

if(sigaction(SIGINT,&act_int,NULL)==-1)

bail(“SIGALRM handler setting fails.”);

}

/*统计ping命令的检测结果*/

void get_statistics(int nsent,int nrecv)

{

printf(“— %s ping statistics —\n”,inet_ntoa(dest.sin_addr)); /*将网络地址转换成“.”点隔的字符串格式。*/

printf(“%d packets tranitted, %d received, %0.0f%% “”packet loss\n”,

nsent,nrecv,1.0*(nsent-nrecv)/nsent*100);

}

/*错误报告*/

void bail(const char * on_what)

{

fputs(strerror(errno),stderr); /*:向指定的文件写入一个字符串(不写入字符串结束标记符‘\0’)。成功写入一个字符串后,文件的位置指针会自动后移,函数返回值为0;否则返回EOR(符号常量,其值为-1)。*/

fputs(“:”,stderr);

fputs(on_what,stderr);

fputc(‘\n’,stderr); /*送一个字符到一个流中*/

exit(1);

}

/*SIGINT(中断信号)处理程序*/

void int_handler(int sig)

{

get_statistics(nsent,nrecv); /*统计ping命令的检测结果*/

close(sockfd); /*关闭网络套接字*/

exit(1);

}

/*SIGALRM(终止进程)处理程序*/

void alarm_handler(int signo)

{

send_ping(); /*发送ping消息*/

}

程序执行:

1、程序编译。在linux终端下执行如下命令:

gcc ping.h -o myping -std=gnu99

因为原始套接字的创建需要root用户权限,所以为了能让所有的其他用户也可以使用该程序,需要通过如下命令设置myping的set-user-id位:

linux下pid_t的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux下pid_t,学习笔记:如何使用Linux下的pid_t数据类型,在linux中兑现ping部分功能怎么解决的信息别忘了在本站进行查找喔。


数据运维技术 » 学习笔记:如何使用Linux下的pid_t数据类型 (linux下pid_t)